1 // Copyright 2016 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_docenvironment.h"
8
9 #include <memory>
10
11 #include "core/fpdfapi/parser/cpdf_array.h"
12 #include "core/fpdfapi/parser/cpdf_stream_acc.h"
13 #include "core/fpdfapi/parser/cpdf_string.h"
14 #include "core/fxcrt/retain_ptr.h"
15 #include "fpdfsdk/cpdfsdk_formfillenvironment.h"
16 #include "fpdfsdk/cpdfsdk_interform.h"
17 #include "fpdfsdk/cpdfsdk_pageview.h"
18 #include "fpdfsdk/fpdfxfa/cpdfxfa_context.h"
19 #include "fpdfsdk/fpdfxfa/cpdfxfa_page.h"
20 #include "fxjs/ijs_runtime.h"
21 #include "xfa/fxfa/cxfa_ffdocview.h"
22 #include "xfa/fxfa/cxfa_ffwidget.h"
23 #include "xfa/fxfa/cxfa_ffwidgethandler.h"
24 #include "xfa/fxfa/cxfa_widgetacciterator.h"
25 #include "xfa/fxfa/parser/cxfa_submit.h"
26
27 #define IDS_XFA_Validate_Input \
28 "At least one required field was empty. Please fill in the required " \
29 "fields\r\n(highlighted) before continuing."
30
31 // submit
32 #define FXFA_CONFIG 0x00000001
33 #define FXFA_TEMPLATE 0x00000010
34 #define FXFA_LOCALESET 0x00000100
35 #define FXFA_DATASETS 0x00001000
36 #define FXFA_XMPMETA 0x00010000
37 #define FXFA_XFDF 0x00100000
38 #define FXFA_FORM 0x01000000
39 #define FXFA_PDF 0x10000000
40 #define FXFA_XFA_ALL 0x01111111
41
CPDFXFA_DocEnvironment(CPDFXFA_Context * pContext)42 CPDFXFA_DocEnvironment::CPDFXFA_DocEnvironment(CPDFXFA_Context* pContext)
43 : m_pContext(pContext) {
44 ASSERT(m_pContext);
45 }
46
~CPDFXFA_DocEnvironment()47 CPDFXFA_DocEnvironment::~CPDFXFA_DocEnvironment() {}
48
SetChangeMark(CXFA_FFDoc * hDoc)49 void CPDFXFA_DocEnvironment::SetChangeMark(CXFA_FFDoc* hDoc) {
50 if (hDoc == m_pContext->GetXFADoc() && m_pContext->GetFormFillEnv())
51 m_pContext->GetFormFillEnv()->SetChangeMark();
52 }
53
InvalidateRect(CXFA_FFPageView * pPageView,const CFX_RectF & rt)54 void CPDFXFA_DocEnvironment::InvalidateRect(CXFA_FFPageView* pPageView,
55 const CFX_RectF& rt) {
56 if (!m_pContext->GetXFADoc() || !m_pContext->GetFormFillEnv())
57 return;
58
59 if (m_pContext->GetFormType() != FormType::kXFAFull)
60 return;
61
62 RetainPtr<CPDFXFA_Page> pPage = m_pContext->GetXFAPage(pPageView);
63 if (!pPage)
64 return;
65
66 CPDFSDK_FormFillEnvironment* pFormFillEnv = m_pContext->GetFormFillEnv();
67 if (!pFormFillEnv)
68 return;
69
70 pFormFillEnv->Invalidate(pPage.Get(), rt.ToFloatRect().ToFxRect());
71 }
72
DisplayCaret(CXFA_FFWidget * hWidget,bool bVisible,const CFX_RectF * pRtAnchor)73 void CPDFXFA_DocEnvironment::DisplayCaret(CXFA_FFWidget* hWidget,
74 bool bVisible,
75 const CFX_RectF* pRtAnchor) {
76 if (!hWidget || !pRtAnchor || !m_pContext->GetXFADoc() ||
77 !m_pContext->GetFormFillEnv() || !m_pContext->GetXFADocView())
78 return;
79
80 if (m_pContext->GetFormType() != FormType::kXFAFull)
81 return;
82
83 CXFA_FFWidgetHandler* pWidgetHandler =
84 m_pContext->GetXFADocView()->GetWidgetHandler();
85 if (!pWidgetHandler)
86 return;
87
88 CXFA_FFPageView* pPageView = hWidget->GetPageView();
89 if (!pPageView)
90 return;
91
92 RetainPtr<CPDFXFA_Page> pPage = m_pContext->GetXFAPage(pPageView);
93 if (!pPage)
94 return;
95
96 CPDFSDK_FormFillEnvironment* pFormFillEnv = m_pContext->GetFormFillEnv();
97 if (!pFormFillEnv)
98 return;
99
100 CFX_FloatRect rcCaret = pRtAnchor->ToFloatRect();
101 pFormFillEnv->DisplayCaret(pPage.Get(), bVisible, rcCaret.left, rcCaret.top,
102 rcCaret.right, rcCaret.bottom);
103 }
104
GetPopupPos(CXFA_FFWidget * hWidget,float fMinPopup,float fMaxPopup,const CFX_RectF & rtAnchor,CFX_RectF & rtPopup)105 bool CPDFXFA_DocEnvironment::GetPopupPos(CXFA_FFWidget* hWidget,
106 float fMinPopup,
107 float fMaxPopup,
108 const CFX_RectF& rtAnchor,
109 CFX_RectF& rtPopup) {
110 if (!hWidget)
111 return false;
112
113 CXFA_FFPageView* pXFAPageView = hWidget->GetPageView();
114 if (!pXFAPageView)
115 return false;
116
117 RetainPtr<CPDFXFA_Page> pPage = m_pContext->GetXFAPage(pXFAPageView);
118 if (!pPage)
119 return false;
120
121 CPDFSDK_FormFillEnvironment* pFormFillEnv = m_pContext->GetFormFillEnv();
122 if (!pFormFillEnv)
123 return false;
124
125 FS_RECTF pageViewRect = {0.0f, 0.0f, 0.0f, 0.0f};
126 pFormFillEnv->GetPageViewRect(pPage.Get(), pageViewRect);
127
128 int t1;
129 int t2;
130 CFX_FloatRect rcAnchor = rtAnchor.ToFloatRect();
131 int nRotate = hWidget->GetNode()->GetRotate();
132 switch (nRotate) {
133 case 90: {
134 t1 = (int)(pageViewRect.right - rcAnchor.right);
135 t2 = (int)(rcAnchor.left - pageViewRect.left);
136 if (rcAnchor.bottom < pageViewRect.bottom)
137 rtPopup.left += rcAnchor.bottom - pageViewRect.bottom;
138 break;
139 }
140 case 180: {
141 t2 = (int)(pageViewRect.top - rcAnchor.top);
142 t1 = (int)(rcAnchor.bottom - pageViewRect.bottom);
143 if (rcAnchor.left < pageViewRect.left)
144 rtPopup.left += rcAnchor.left - pageViewRect.left;
145 break;
146 }
147 case 270: {
148 t1 = (int)(rcAnchor.left - pageViewRect.left);
149 t2 = (int)(pageViewRect.right - rcAnchor.right);
150 if (rcAnchor.top > pageViewRect.top)
151 rtPopup.left -= rcAnchor.top - pageViewRect.top;
152 break;
153 }
154 case 0:
155 default: {
156 t1 = (int)(pageViewRect.top - rcAnchor.top);
157 t2 = (int)(rcAnchor.bottom - pageViewRect.bottom);
158 if (rcAnchor.right > pageViewRect.right)
159 rtPopup.left -= rcAnchor.right - pageViewRect.right;
160 break;
161 }
162 }
163
164 int t;
165 uint32_t dwPos;
166 if (t1 <= 0 && t2 <= 0)
167 return false;
168 if (t1 <= 0) {
169 t = t2;
170 dwPos = 1;
171 } else if (t2 <= 0) {
172 t = t1;
173 dwPos = 0;
174 } else if (t1 > t2) {
175 t = t1;
176 dwPos = 0;
177 } else {
178 t = t2;
179 dwPos = 1;
180 }
181
182 float fPopupHeight;
183 if (t < fMinPopup)
184 fPopupHeight = fMinPopup;
185 else if (t > fMaxPopup)
186 fPopupHeight = fMaxPopup;
187 else
188 fPopupHeight = static_cast<float>(t);
189
190 switch (nRotate) {
191 case 0:
192 case 180: {
193 if (dwPos == 0) {
194 rtPopup.top = rtAnchor.height;
195 rtPopup.height = fPopupHeight;
196 } else {
197 rtPopup.top = -fPopupHeight;
198 rtPopup.height = fPopupHeight;
199 }
200 break;
201 }
202 case 90:
203 case 270: {
204 if (dwPos == 0) {
205 rtPopup.top = rtAnchor.width;
206 rtPopup.height = fPopupHeight;
207 } else {
208 rtPopup.top = -fPopupHeight;
209 rtPopup.height = fPopupHeight;
210 }
211 break;
212 }
213 default:
214 break;
215 }
216
217 return true;
218 }
219
PopupMenu(CXFA_FFWidget * hWidget,CFX_PointF ptPopup)220 bool CPDFXFA_DocEnvironment::PopupMenu(CXFA_FFWidget* hWidget,
221 CFX_PointF ptPopup) {
222 if (!hWidget)
223 return false;
224
225 CXFA_FFPageView* pXFAPageView = hWidget->GetPageView();
226 if (!pXFAPageView)
227 return false;
228
229 RetainPtr<CPDFXFA_Page> pPage = m_pContext->GetXFAPage(pXFAPageView);
230 if (!pPage)
231 return false;
232
233 CPDFSDK_FormFillEnvironment* pFormFillEnv = m_pContext->GetFormFillEnv();
234 if (!pFormFillEnv)
235 return false;
236
237 int menuFlag = 0;
238 if (hWidget->CanUndo())
239 menuFlag |= FXFA_MENU_UNDO;
240 if (hWidget->CanRedo())
241 menuFlag |= FXFA_MENU_REDO;
242 if (hWidget->CanPaste())
243 menuFlag |= FXFA_MENU_PASTE;
244 if (hWidget->CanCopy())
245 menuFlag |= FXFA_MENU_COPY;
246 if (hWidget->CanCut())
247 menuFlag |= FXFA_MENU_CUT;
248 if (hWidget->CanSelectAll())
249 menuFlag |= FXFA_MENU_SELECTALL;
250
251 return pFormFillEnv->PopupMenu(pPage.Get(), hWidget, menuFlag, ptPopup);
252 }
253
PageViewEvent(CXFA_FFPageView * pPageView,uint32_t dwFlags)254 void CPDFXFA_DocEnvironment::PageViewEvent(CXFA_FFPageView* pPageView,
255 uint32_t dwFlags) {
256 CPDFSDK_FormFillEnvironment* pFormFillEnv = m_pContext->GetFormFillEnv();
257 if (!pFormFillEnv)
258 return;
259
260 if (m_pContext->GetLoadStatus() == FXFA_LOADSTATUS_LOADING ||
261 m_pContext->GetLoadStatus() == FXFA_LOADSTATUS_CLOSING ||
262 XFA_PAGEVIEWEVENT_StopLayout != dwFlags)
263 return;
264
265 int nNewCount = m_pContext->GetPageCount();
266 if (nNewCount == m_pContext->GetOriginalPageCount())
267 return;
268
269 CXFA_FFDocView* pXFADocView = m_pContext->GetXFADocView();
270 if (!pXFADocView)
271 return;
272
273 for (int iPageIter = 0; iPageIter < m_pContext->GetOriginalPageCount();
274 iPageIter++) {
275 RetainPtr<CPDFXFA_Page> pPage = (*m_pContext->GetXFAPageList())[iPageIter];
276 if (!pPage)
277 continue;
278
279 m_pContext->GetFormFillEnv()->RemovePageView(pPage.Get());
280 pPage->SetXFAPageView(pXFADocView->GetPageView(iPageIter));
281 }
282
283 int flag = (nNewCount < m_pContext->GetOriginalPageCount())
284 ? FXFA_PAGEVIEWEVENT_POSTREMOVED
285 : FXFA_PAGEVIEWEVENT_POSTADDED;
286 int count = abs(nNewCount - m_pContext->GetOriginalPageCount());
287 m_pContext->SetOriginalPageCount(nNewCount);
288 pFormFillEnv->PageEvent(count, flag);
289 }
290
WidgetPostAdd(CXFA_FFWidget * hWidget,CXFA_WidgetAcc * pWidgetAcc)291 void CPDFXFA_DocEnvironment::WidgetPostAdd(CXFA_FFWidget* hWidget,
292 CXFA_WidgetAcc* pWidgetAcc) {
293 if (m_pContext->GetFormType() != FormType::kXFAFull || !hWidget)
294 return;
295
296 CXFA_FFPageView* pPageView = hWidget->GetPageView();
297 if (!pPageView)
298 return;
299
300 RetainPtr<CPDFXFA_Page> pXFAPage = m_pContext->GetXFAPage(pPageView);
301 if (!pXFAPage)
302 return;
303
304 m_pContext->GetFormFillEnv()
305 ->GetPageView(pXFAPage.Get(), true)
306 ->AddAnnot(hWidget);
307 }
308
WidgetPreRemove(CXFA_FFWidget * hWidget,CXFA_WidgetAcc * pWidgetAcc)309 void CPDFXFA_DocEnvironment::WidgetPreRemove(CXFA_FFWidget* hWidget,
310 CXFA_WidgetAcc* pWidgetAcc) {
311 if (m_pContext->GetFormType() != FormType::kXFAFull || !hWidget)
312 return;
313
314 CXFA_FFPageView* pPageView = hWidget->GetPageView();
315 if (!pPageView)
316 return;
317
318 RetainPtr<CPDFXFA_Page> pXFAPage = m_pContext->GetXFAPage(pPageView);
319 if (!pXFAPage)
320 return;
321
322 CPDFSDK_PageView* pSdkPageView =
323 m_pContext->GetFormFillEnv()->GetPageView(pXFAPage.Get(), true);
324 CPDFSDK_Annot* pAnnot = pSdkPageView->GetAnnotByXFAWidget(hWidget);
325 if (pAnnot)
326 pSdkPageView->DeleteAnnot(pAnnot);
327 }
328
CountPages(CXFA_FFDoc * hDoc)329 int32_t CPDFXFA_DocEnvironment::CountPages(CXFA_FFDoc* hDoc) {
330 if (hDoc == m_pContext->GetXFADoc() && m_pContext->GetFormFillEnv())
331 return m_pContext->GetPageCount();
332 return 0;
333 }
334
GetCurrentPage(CXFA_FFDoc * hDoc)335 int32_t CPDFXFA_DocEnvironment::GetCurrentPage(CXFA_FFDoc* hDoc) {
336 if (hDoc != m_pContext->GetXFADoc() || !m_pContext->GetFormFillEnv())
337 return -1;
338 if (m_pContext->GetFormType() != FormType::kXFAFull)
339 return -1;
340
341 CPDFSDK_FormFillEnvironment* pFormFillEnv = m_pContext->GetFormFillEnv();
342 if (!pFormFillEnv)
343 return -1;
344
345 return pFormFillEnv->GetCurrentPageIndex(m_pContext.Get());
346 }
347
SetCurrentPage(CXFA_FFDoc * hDoc,int32_t iCurPage)348 void CPDFXFA_DocEnvironment::SetCurrentPage(CXFA_FFDoc* hDoc,
349 int32_t iCurPage) {
350 if (hDoc != m_pContext->GetXFADoc() || !m_pContext->GetFormFillEnv() ||
351 m_pContext->GetFormType() != FormType::kXFAFull || iCurPage < 0 ||
352 iCurPage >= m_pContext->GetFormFillEnv()->GetPageCount()) {
353 return;
354 }
355
356 CPDFSDK_FormFillEnvironment* pFormFillEnv = m_pContext->GetFormFillEnv();
357 if (!pFormFillEnv)
358 return;
359 pFormFillEnv->SetCurrentPage(m_pContext.Get(), iCurPage);
360 }
361
IsCalculationsEnabled(CXFA_FFDoc * hDoc)362 bool CPDFXFA_DocEnvironment::IsCalculationsEnabled(CXFA_FFDoc* hDoc) {
363 if (hDoc != m_pContext->GetXFADoc() || !m_pContext->GetFormFillEnv())
364 return false;
365 if (m_pContext->GetFormFillEnv()->GetInterForm()) {
366 return m_pContext->GetFormFillEnv()
367 ->GetInterForm()
368 ->IsXfaCalculateEnabled();
369 }
370 return false;
371 }
372
SetCalculationsEnabled(CXFA_FFDoc * hDoc,bool bEnabled)373 void CPDFXFA_DocEnvironment::SetCalculationsEnabled(CXFA_FFDoc* hDoc,
374 bool bEnabled) {
375 if (hDoc != m_pContext->GetXFADoc() || !m_pContext->GetFormFillEnv())
376 return;
377 if (m_pContext->GetFormFillEnv()->GetInterForm()) {
378 m_pContext->GetFormFillEnv()->GetInterForm()->XfaEnableCalculate(bEnabled);
379 }
380 }
381
GetTitle(CXFA_FFDoc * hDoc,WideString & wsTitle)382 void CPDFXFA_DocEnvironment::GetTitle(CXFA_FFDoc* hDoc, WideString& wsTitle) {
383 if (hDoc != m_pContext->GetXFADoc() || !m_pContext->GetPDFDoc())
384 return;
385
386 const CPDF_Dictionary* pInfoDict = m_pContext->GetPDFDoc()->GetInfo();
387 if (!pInfoDict)
388 return;
389
390 ByteString csTitle = pInfoDict->GetStringFor("Title");
391 wsTitle = wsTitle.FromLocal(csTitle.GetBuffer(csTitle.GetLength()));
392 csTitle.ReleaseBuffer(csTitle.GetLength());
393 }
394
SetTitle(CXFA_FFDoc * hDoc,const WideString & wsTitle)395 void CPDFXFA_DocEnvironment::SetTitle(CXFA_FFDoc* hDoc,
396 const WideString& wsTitle) {
397 if (hDoc != m_pContext->GetXFADoc() || !m_pContext->GetPDFDoc())
398 return;
399
400 CPDF_Dictionary* pInfoDict = m_pContext->GetPDFDoc()->GetInfo();
401 if (pInfoDict)
402 pInfoDict->SetNewFor<CPDF_String>("Title", wsTitle);
403 }
404
ExportData(CXFA_FFDoc * hDoc,const WideString & wsFilePath,bool bXDP)405 void CPDFXFA_DocEnvironment::ExportData(CXFA_FFDoc* hDoc,
406 const WideString& wsFilePath,
407 bool bXDP) {
408 if (hDoc != m_pContext->GetXFADoc())
409 return;
410
411 if (!m_pContext->ContainsXFAForm())
412 return;
413
414 CPDFSDK_FormFillEnvironment* pFormFillEnv = m_pContext->GetFormFillEnv();
415 if (!pFormFillEnv)
416 return;
417
418 int fileType = bXDP ? FXFA_SAVEAS_XDP : FXFA_SAVEAS_XML;
419 ByteString bs = wsFilePath.UTF16LE_Encode();
420 if (wsFilePath.IsEmpty()) {
421 if (!pFormFillEnv->GetFormFillInfo() ||
422 !pFormFillEnv->GetFormFillInfo()->m_pJsPlatform) {
423 return;
424 }
425
426 WideString filepath = pFormFillEnv->JS_fieldBrowse();
427 bs = filepath.UTF16LE_Encode();
428 }
429 int len = bs.GetLength();
430 FPDF_FILEHANDLER* pFileHandler =
431 pFormFillEnv->OpenFile(bXDP ? FXFA_SAVEAS_XDP : FXFA_SAVEAS_XML,
432 (FPDF_WIDESTRING)bs.GetBuffer(len), "wb");
433 bs.ReleaseBuffer(len);
434 if (!pFileHandler)
435 return;
436
437 RetainPtr<IFX_SeekableStream> fileWrite = MakeSeekableStream(pFileHandler);
438 if (fileType == FXFA_SAVEAS_XML) {
439 ByteString content = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n";
440 fileWrite->WriteBlock(content.c_str(), fileWrite->GetSize(),
441 content.GetLength());
442 CXFA_FFDoc* ffdoc = m_pContext->GetXFADocView()->GetDoc();
443 ffdoc->SavePackage(
444 ToNode(ffdoc->GetXFADoc()->GetXFAObject(XFA_HASHCODE_Data)), fileWrite,
445 nullptr);
446 } else if (fileType == FXFA_SAVEAS_XDP) {
447 if (!m_pContext->GetPDFDoc())
448 return;
449
450 const CPDF_Dictionary* pRoot = m_pContext->GetPDFDoc()->GetRoot();
451 if (!pRoot)
452 return;
453
454 CPDF_Dictionary* pAcroForm = pRoot->GetDictFor("AcroForm");
455 if (!pAcroForm)
456 return;
457
458 CPDF_Array* pArray = ToArray(pAcroForm->GetObjectFor("XFA"));
459 if (!pArray)
460 return;
461
462 int size = pArray->GetCount();
463 for (int i = 1; i < size; i += 2) {
464 CPDF_Object* pPDFObj = pArray->GetObjectAt(i);
465 CPDF_Object* pPrePDFObj = pArray->GetObjectAt(i - 1);
466 if (!pPrePDFObj->IsString())
467 continue;
468 if (!pPDFObj->IsReference())
469 continue;
470
471 CPDF_Stream* pStream = ToStream(pPDFObj->GetDirect());
472 if (!pStream)
473 continue;
474 if (pPrePDFObj->GetString() == "form") {
475 CXFA_FFDoc* ffdoc = m_pContext->GetXFADocView()->GetDoc();
476 ffdoc->SavePackage(
477 ToNode(ffdoc->GetXFADoc()->GetXFAObject(XFA_HASHCODE_Form)),
478 fileWrite, nullptr);
479 continue;
480 }
481 if (pPrePDFObj->GetString() == "datasets") {
482 CXFA_FFDoc* ffdoc = m_pContext->GetXFADocView()->GetDoc();
483 ffdoc->SavePackage(
484 ToNode(ffdoc->GetXFADoc()->GetXFAObject(XFA_HASHCODE_Datasets)),
485 fileWrite, nullptr);
486 continue;
487 }
488 if (i == size - 1) {
489 WideString wPath = WideString::FromUTF16LE(
490 reinterpret_cast<const unsigned short*>(bs.c_str()),
491 bs.GetLength() / sizeof(unsigned short));
492 ByteString bPath = wPath.UTF8Encode();
493 const char* szFormat =
494 "\n<pdf href=\"%s\" xmlns=\"http://ns.adobe.com/xdp/pdf/\"/>";
495 ByteString content = ByteString::Format(szFormat, bPath.c_str());
496 fileWrite->WriteBlock(content.c_str(), fileWrite->GetSize(),
497 content.GetLength());
498 }
499 auto pAcc = pdfium::MakeRetain<CPDF_StreamAcc>(pStream);
500 pAcc->LoadAllDataFiltered();
501 fileWrite->WriteBlock(pAcc->GetData(), fileWrite->GetSize(),
502 pAcc->GetSize());
503 }
504 }
505 fileWrite->Flush();
506 }
507
GotoURL(CXFA_FFDoc * hDoc,const WideString & bsURL)508 void CPDFXFA_DocEnvironment::GotoURL(CXFA_FFDoc* hDoc,
509 const WideString& bsURL) {
510 if (hDoc != m_pContext->GetXFADoc())
511 return;
512
513 if (m_pContext->GetFormType() != FormType::kXFAFull)
514 return;
515
516 CPDFSDK_FormFillEnvironment* pFormFillEnv = m_pContext->GetFormFillEnv();
517 if (!pFormFillEnv)
518 return;
519
520 WideStringView str(bsURL.c_str());
521 pFormFillEnv->GotoURL(m_pContext.Get(), str);
522 }
523
IsValidationsEnabled(CXFA_FFDoc * hDoc)524 bool CPDFXFA_DocEnvironment::IsValidationsEnabled(CXFA_FFDoc* hDoc) {
525 if (hDoc != m_pContext->GetXFADoc() || !m_pContext->GetFormFillEnv())
526 return false;
527 if (m_pContext->GetFormFillEnv()->GetInterForm()) {
528 return m_pContext->GetFormFillEnv()
529 ->GetInterForm()
530 ->IsXfaValidationsEnabled();
531 }
532 return true;
533 }
534
SetValidationsEnabled(CXFA_FFDoc * hDoc,bool bEnabled)535 void CPDFXFA_DocEnvironment::SetValidationsEnabled(CXFA_FFDoc* hDoc,
536 bool bEnabled) {
537 if (hDoc != m_pContext->GetXFADoc() || !m_pContext->GetFormFillEnv())
538 return;
539 if (m_pContext->GetFormFillEnv()->GetInterForm()) {
540 m_pContext->GetFormFillEnv()->GetInterForm()->XfaSetValidationsEnabled(
541 bEnabled);
542 }
543 }
544
SetFocusWidget(CXFA_FFDoc * hDoc,CXFA_FFWidget * hWidget)545 void CPDFXFA_DocEnvironment::SetFocusWidget(CXFA_FFDoc* hDoc,
546 CXFA_FFWidget* hWidget) {
547 if (hDoc != m_pContext->GetXFADoc())
548 return;
549
550 if (!hWidget) {
551 CPDFSDK_Annot::ObservedPtr pNull;
552 m_pContext->GetFormFillEnv()->SetFocusAnnot(&pNull);
553 return;
554 }
555
556 int pageViewCount = m_pContext->GetFormFillEnv()->GetPageViewCount();
557 for (int i = 0; i < pageViewCount; i++) {
558 CPDFSDK_PageView* pPageView = m_pContext->GetFormFillEnv()->GetPageView(i);
559 if (!pPageView)
560 continue;
561
562 CPDFSDK_Annot::ObservedPtr pAnnot(pPageView->GetAnnotByXFAWidget(hWidget));
563 if (pAnnot) {
564 m_pContext->GetFormFillEnv()->SetFocusAnnot(&pAnnot);
565 break;
566 }
567 }
568 }
569
Print(CXFA_FFDoc * hDoc,int32_t nStartPage,int32_t nEndPage,uint32_t dwOptions)570 void CPDFXFA_DocEnvironment::Print(CXFA_FFDoc* hDoc,
571 int32_t nStartPage,
572 int32_t nEndPage,
573 uint32_t dwOptions) {
574 if (hDoc != m_pContext->GetXFADoc())
575 return;
576
577 CPDFSDK_FormFillEnvironment* pFormFillEnv = m_pContext->GetFormFillEnv();
578 if (!pFormFillEnv || !pFormFillEnv->GetFormFillInfo() ||
579 !pFormFillEnv->GetFormFillInfo()->m_pJsPlatform ||
580 !pFormFillEnv->GetFormFillInfo()->m_pJsPlatform->Doc_print) {
581 return;
582 }
583
584 pFormFillEnv->GetFormFillInfo()->m_pJsPlatform->Doc_print(
585 pFormFillEnv->GetFormFillInfo()->m_pJsPlatform,
586 dwOptions & XFA_PRINTOPT_ShowDialog, nStartPage, nEndPage,
587 dwOptions & XFA_PRINTOPT_CanCancel, dwOptions & XFA_PRINTOPT_ShrinkPage,
588 dwOptions & XFA_PRINTOPT_AsImage, dwOptions & XFA_PRINTOPT_ReverseOrder,
589 dwOptions & XFA_PRINTOPT_PrintAnnot);
590 }
591
GetHighlightColor(CXFA_FFDoc * hDoc)592 FX_ARGB CPDFXFA_DocEnvironment::GetHighlightColor(CXFA_FFDoc* hDoc) {
593 if (hDoc != m_pContext->GetXFADoc() || !m_pContext->GetFormFillEnv())
594 return 0;
595
596 CPDFSDK_InterForm* pInterForm = m_pContext->GetFormFillEnv()->GetInterForm();
597 if (!pInterForm)
598 return 0;
599
600 return ArgbEncode(pInterForm->GetHighlightAlpha(),
601 pInterForm->GetHighlightColor(FormFieldType::kXFA));
602 }
603
NotifySubmit(bool bPrevOrPost)604 bool CPDFXFA_DocEnvironment::NotifySubmit(bool bPrevOrPost) {
605 if (bPrevOrPost)
606 return OnBeforeNotifySubmit();
607
608 OnAfterNotifySubmit();
609 return true;
610 }
611
OnBeforeNotifySubmit()612 bool CPDFXFA_DocEnvironment::OnBeforeNotifySubmit() {
613 if (!m_pContext->ContainsXFAForm())
614 return true;
615
616 CXFA_FFDocView* docView = m_pContext->GetXFADocView();
617 if (!docView)
618 return true;
619
620 CXFA_FFWidgetHandler* pWidgetHandler = docView->GetWidgetHandler();
621 if (!pWidgetHandler)
622 return true;
623
624 std::unique_ptr<CXFA_WidgetAccIterator> pWidgetAccIterator =
625 docView->CreateWidgetAccIterator();
626 if (pWidgetAccIterator) {
627 CXFA_EventParam Param;
628 Param.m_eType = XFA_EVENT_PreSubmit;
629 while (CXFA_WidgetAcc* pWidgetAcc = pWidgetAccIterator->MoveToNext())
630 pWidgetHandler->ProcessEvent(pWidgetAcc, &Param);
631 }
632
633 pWidgetAccIterator = docView->CreateWidgetAccIterator();
634 if (!pWidgetAccIterator)
635 return true;
636
637 CXFA_WidgetAcc* pWidgetAcc = pWidgetAccIterator->MoveToNext();
638 pWidgetAcc = pWidgetAccIterator->MoveToNext();
639 while (pWidgetAcc) {
640 int fRet = pWidgetAcc->GetNode()->ProcessValidate(docView, -1);
641 if (fRet == XFA_EVENTERROR_Error) {
642 CPDFSDK_FormFillEnvironment* pFormFillEnv = m_pContext->GetFormFillEnv();
643 if (!pFormFillEnv)
644 return false;
645
646 WideString ws = WideString::FromLocal(IDS_XFA_Validate_Input);
647 ByteString bs = ws.UTF16LE_Encode();
648 int len = bs.GetLength();
649 pFormFillEnv->Alert((FPDF_WIDESTRING)bs.GetBuffer(len),
650 (FPDF_WIDESTRING)L"", 0, 1);
651 bs.ReleaseBuffer(len);
652 return false;
653 }
654 pWidgetAcc = pWidgetAccIterator->MoveToNext();
655 }
656 docView->UpdateDocView();
657
658 return true;
659 }
660
OnAfterNotifySubmit()661 void CPDFXFA_DocEnvironment::OnAfterNotifySubmit() {
662 if (!m_pContext->ContainsXFAForm())
663 return;
664
665 if (!m_pContext->GetXFADocView())
666 return;
667
668 CXFA_FFWidgetHandler* pWidgetHandler =
669 m_pContext->GetXFADocView()->GetWidgetHandler();
670 if (!pWidgetHandler)
671 return;
672
673 std::unique_ptr<CXFA_WidgetAccIterator> pWidgetAccIterator =
674 m_pContext->GetXFADocView()->CreateWidgetAccIterator();
675 if (!pWidgetAccIterator)
676 return;
677
678 CXFA_EventParam Param;
679 Param.m_eType = XFA_EVENT_PostSubmit;
680 CXFA_WidgetAcc* pWidgetAcc = pWidgetAccIterator->MoveToNext();
681 while (pWidgetAcc) {
682 pWidgetHandler->ProcessEvent(pWidgetAcc, &Param);
683 pWidgetAcc = pWidgetAccIterator->MoveToNext();
684 }
685 m_pContext->GetXFADocView()->UpdateDocView();
686 }
687
Submit(CXFA_FFDoc * hDoc,CXFA_Submit * submit)688 bool CPDFXFA_DocEnvironment::Submit(CXFA_FFDoc* hDoc, CXFA_Submit* submit) {
689 if (!NotifySubmit(true) || !m_pContext->GetXFADocView())
690 return false;
691
692 m_pContext->GetXFADocView()->UpdateDocView();
693 bool ret = SubmitInternal(hDoc, submit);
694 NotifySubmit(false);
695 return ret;
696 }
697
OpenLinkedFile(CXFA_FFDoc * hDoc,const WideString & wsLink)698 RetainPtr<IFX_SeekableReadStream> CPDFXFA_DocEnvironment::OpenLinkedFile(
699 CXFA_FFDoc* hDoc,
700 const WideString& wsLink) {
701 CPDFSDK_FormFillEnvironment* pFormFillEnv = m_pContext->GetFormFillEnv();
702 if (!pFormFillEnv)
703 return nullptr;
704
705 ByteString bs = wsLink.UTF16LE_Encode();
706 int len = bs.GetLength();
707 FPDF_FILEHANDLER* pFileHandler =
708 pFormFillEnv->OpenFile(0, (FPDF_WIDESTRING)bs.GetBuffer(len), "rb");
709 bs.ReleaseBuffer(len);
710 if (!pFileHandler)
711 return nullptr;
712
713 return MakeSeekableStream(pFileHandler);
714 }
715
ExportSubmitFile(FPDF_FILEHANDLER * pFileHandler,int fileType,FPDF_DWORD encodeType,FPDF_DWORD flag)716 bool CPDFXFA_DocEnvironment::ExportSubmitFile(FPDF_FILEHANDLER* pFileHandler,
717 int fileType,
718 FPDF_DWORD encodeType,
719 FPDF_DWORD flag) {
720 if (!m_pContext->GetXFADocView())
721 return false;
722
723 CPDFSDK_FormFillEnvironment* pFormFillEnv = m_pContext->GetFormFillEnv();
724 if (!pFormFillEnv)
725 return false;
726
727 CXFA_FFDoc* ffdoc = m_pContext->GetXFADocView()->GetDoc();
728 RetainPtr<IFX_SeekableStream> fileStream = MakeSeekableStream(pFileHandler);
729 if (fileType == FXFA_SAVEAS_XML) {
730 static constexpr char kContent[] =
731 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n";
732 fileStream->WriteBlock(kContent, 0, strlen(kContent));
733
734 ffdoc->SavePackage(
735 ToNode(ffdoc->GetXFADoc()->GetXFAObject(XFA_HASHCODE_Data)), fileStream,
736 nullptr);
737 return true;
738 }
739
740 if (fileType != FXFA_SAVEAS_XDP)
741 return true;
742
743 if (!flag) {
744 flag = FXFA_CONFIG | FXFA_TEMPLATE | FXFA_LOCALESET | FXFA_DATASETS |
745 FXFA_XMPMETA | FXFA_XFDF | FXFA_FORM;
746 }
747 if (!m_pContext->GetPDFDoc()) {
748 fileStream->Flush();
749 return false;
750 }
751
752 const CPDF_Dictionary* pRoot = m_pContext->GetPDFDoc()->GetRoot();
753 if (!pRoot) {
754 fileStream->Flush();
755 return false;
756 }
757
758 CPDF_Dictionary* pAcroForm = pRoot->GetDictFor("AcroForm");
759 if (!pAcroForm) {
760 fileStream->Flush();
761 return false;
762 }
763
764 CPDF_Array* pArray = ToArray(pAcroForm->GetObjectFor("XFA"));
765 if (!pArray) {
766 fileStream->Flush();
767 return false;
768 }
769
770 int size = pArray->GetCount();
771 for (int i = 1; i < size; i += 2) {
772 CPDF_Object* pPDFObj = pArray->GetObjectAt(i);
773 CPDF_Object* pPrePDFObj = pArray->GetObjectAt(i - 1);
774 if (!pPrePDFObj->IsString())
775 continue;
776 if (!pPDFObj->IsReference())
777 continue;
778
779 CPDF_Object* pDirectObj = pPDFObj->GetDirect();
780 if (!pDirectObj->IsStream())
781 continue;
782 if (pPrePDFObj->GetString() == "config" && !(flag & FXFA_CONFIG))
783 continue;
784 if (pPrePDFObj->GetString() == "template" && !(flag & FXFA_TEMPLATE))
785 continue;
786 if (pPrePDFObj->GetString() == "localeSet" && !(flag & FXFA_LOCALESET))
787 continue;
788 if (pPrePDFObj->GetString() == "datasets" && !(flag & FXFA_DATASETS))
789 continue;
790 if (pPrePDFObj->GetString() == "xmpmeta" && !(flag & FXFA_XMPMETA))
791 continue;
792 if (pPrePDFObj->GetString() == "xfdf" && !(flag & FXFA_XFDF))
793 continue;
794 if (pPrePDFObj->GetString() == "form" && !(flag & FXFA_FORM))
795 continue;
796
797 if (pPrePDFObj->GetString() == "form") {
798 ffdoc->SavePackage(
799 ToNode(ffdoc->GetXFADoc()->GetXFAObject(XFA_HASHCODE_Form)),
800 fileStream, nullptr);
801 } else if (pPrePDFObj->GetString() == "datasets") {
802 ffdoc->SavePackage(
803 ToNode(ffdoc->GetXFADoc()->GetXFAObject(XFA_HASHCODE_Datasets)),
804 fileStream, nullptr);
805 }
806 }
807 return true;
808 }
809
ToXFAContentFlags(WideString csSrcContent,FPDF_DWORD & flag)810 void CPDFXFA_DocEnvironment::ToXFAContentFlags(WideString csSrcContent,
811 FPDF_DWORD& flag) {
812 if (csSrcContent.Contains(L" config "))
813 flag |= FXFA_CONFIG;
814 if (csSrcContent.Contains(L" template "))
815 flag |= FXFA_TEMPLATE;
816 if (csSrcContent.Contains(L" localeSet "))
817 flag |= FXFA_LOCALESET;
818 if (csSrcContent.Contains(L" datasets "))
819 flag |= FXFA_DATASETS;
820 if (csSrcContent.Contains(L" xmpmeta "))
821 flag |= FXFA_XMPMETA;
822 if (csSrcContent.Contains(L" xfdf "))
823 flag |= FXFA_XFDF;
824 if (csSrcContent.Contains(L" form "))
825 flag |= FXFA_FORM;
826 if (flag == 0) {
827 flag = FXFA_CONFIG | FXFA_TEMPLATE | FXFA_LOCALESET | FXFA_DATASETS |
828 FXFA_XMPMETA | FXFA_XFDF | FXFA_FORM;
829 }
830 }
831
MailToInfo(WideString & csURL,WideString & csToAddress,WideString & csCCAddress,WideString & csBCCAddress,WideString & csSubject,WideString & csMsg)832 bool CPDFXFA_DocEnvironment::MailToInfo(WideString& csURL,
833 WideString& csToAddress,
834 WideString& csCCAddress,
835 WideString& csBCCAddress,
836 WideString& csSubject,
837 WideString& csMsg) {
838 WideString srcURL = csURL;
839 srcURL.TrimLeft();
840 if (srcURL.Left(7).CompareNoCase(L"mailto:") != 0)
841 return false;
842
843 auto pos = srcURL.Find(L'?');
844 WideString tmp;
845 if (!pos.has_value()) {
846 pos = srcURL.Find(L'@');
847 if (!pos.has_value())
848 return false;
849
850 tmp = srcURL.Right(csURL.GetLength() - 7);
851 } else {
852 tmp = srcURL.Left(pos.value());
853 tmp = tmp.Right(tmp.GetLength() - 7);
854 }
855 tmp.Trim();
856
857 csToAddress = tmp;
858
859 srcURL = srcURL.Right(srcURL.GetLength() - (pos.value() + 1));
860 while (!srcURL.IsEmpty()) {
861 srcURL.Trim();
862 pos = srcURL.Find(L'&');
863
864 tmp = (!pos.has_value()) ? srcURL : srcURL.Left(pos.value());
865 tmp.Trim();
866 if (tmp.GetLength() >= 3 && tmp.Left(3).CompareNoCase(L"cc=") == 0) {
867 tmp = tmp.Right(tmp.GetLength() - 3);
868 if (!csCCAddress.IsEmpty())
869 csCCAddress += L';';
870 csCCAddress += tmp;
871 } else if (tmp.GetLength() >= 4 &&
872 tmp.Left(4).CompareNoCase(L"bcc=") == 0) {
873 tmp = tmp.Right(tmp.GetLength() - 4);
874 if (!csBCCAddress.IsEmpty())
875 csBCCAddress += L';';
876 csBCCAddress += tmp;
877 } else if (tmp.GetLength() >= 8 &&
878 tmp.Left(8).CompareNoCase(L"subject=") == 0) {
879 tmp = tmp.Right(tmp.GetLength() - 8);
880 csSubject += tmp;
881 } else if (tmp.GetLength() >= 5 &&
882 tmp.Left(5).CompareNoCase(L"body=") == 0) {
883 tmp = tmp.Right(tmp.GetLength() - 5);
884 csMsg += tmp;
885 }
886 srcURL = !pos.has_value()
887 ? L""
888 : srcURL.Right(csURL.GetLength() - (pos.value() + 1));
889 }
890 csToAddress.Replace(L",", L";");
891 csCCAddress.Replace(L",", L";");
892 csBCCAddress.Replace(L",", L";");
893 return true;
894 }
895
SubmitInternal(CXFA_FFDoc * hDoc,CXFA_Submit * submit)896 bool CPDFXFA_DocEnvironment::SubmitInternal(CXFA_FFDoc* hDoc,
897 CXFA_Submit* submit) {
898 CPDFSDK_FormFillEnvironment* pFormFillEnv = m_pContext->GetFormFillEnv();
899 if (!pFormFillEnv)
900 return false;
901
902 WideString csURL = submit->GetSubmitTarget();
903 if (csURL.IsEmpty()) {
904 WideString ws = WideString::FromLocal("Submit cancelled.");
905 ByteString bs = ws.UTF16LE_Encode();
906 int len = bs.GetLength();
907 pFormFillEnv->Alert(reinterpret_cast<FPDF_WIDESTRING>(bs.GetBuffer(len)),
908 reinterpret_cast<FPDF_WIDESTRING>(L""), 0, 4);
909 bs.ReleaseBuffer(len);
910 return false;
911 }
912
913 FPDF_FILEHANDLER* pFileHandler = nullptr;
914 int fileFlag = -1;
915 switch (submit->GetSubmitFormat()) {
916 case XFA_AttributeEnum::Xdp: {
917 WideString csContent = submit->GetSubmitXDPContent();
918 csContent.Trim();
919
920 WideString space = WideString::FromLocal(" ");
921 csContent = space + csContent + space;
922 FPDF_DWORD flag = 0;
923 if (submit->IsSubmitEmbedPDF())
924 flag |= FXFA_PDF;
925
926 ToXFAContentFlags(csContent, flag);
927 pFileHandler = pFormFillEnv->OpenFile(FXFA_SAVEAS_XDP, nullptr, "wb");
928 fileFlag = FXFA_SAVEAS_XDP;
929 ExportSubmitFile(pFileHandler, FXFA_SAVEAS_XDP, 0, flag);
930 break;
931 }
932 case XFA_AttributeEnum::Xml:
933 pFileHandler = pFormFillEnv->OpenFile(FXFA_SAVEAS_XML, nullptr, "wb");
934 fileFlag = FXFA_SAVEAS_XML;
935 ExportSubmitFile(pFileHandler, FXFA_SAVEAS_XML, 0, FXFA_XFA_ALL);
936 break;
937 case XFA_AttributeEnum::Pdf:
938 break;
939 case XFA_AttributeEnum::Urlencoded:
940 pFileHandler = pFormFillEnv->OpenFile(FXFA_SAVEAS_XML, nullptr, "wb");
941 fileFlag = FXFA_SAVEAS_XML;
942 ExportSubmitFile(pFileHandler, FXFA_SAVEAS_XML, 0, FXFA_XFA_ALL);
943 break;
944 default:
945 return false;
946 }
947 if (!pFileHandler)
948 return false;
949
950 if (csURL.Left(7).CompareNoCase(L"mailto:") == 0) {
951 WideString csToAddress;
952 WideString csCCAddress;
953 WideString csBCCAddress;
954 WideString csSubject;
955 WideString csMsg;
956 if (!MailToInfo(csURL, csToAddress, csCCAddress, csBCCAddress, csSubject,
957 csMsg)) {
958 return false;
959 }
960 ByteString bsTo = WideString(csToAddress).UTF16LE_Encode();
961 ByteString bsCC = WideString(csCCAddress).UTF16LE_Encode();
962 ByteString bsBcc = WideString(csBCCAddress).UTF16LE_Encode();
963 ByteString bsSubject = WideString(csSubject).UTF16LE_Encode();
964 ByteString bsMsg = WideString(csMsg).UTF16LE_Encode();
965 FPDF_WIDESTRING pTo = (FPDF_WIDESTRING)bsTo.GetBuffer(bsTo.GetLength());
966 FPDF_WIDESTRING pCC = (FPDF_WIDESTRING)bsCC.GetBuffer(bsCC.GetLength());
967 FPDF_WIDESTRING pBcc = (FPDF_WIDESTRING)bsBcc.GetBuffer(bsBcc.GetLength());
968 FPDF_WIDESTRING pSubject =
969 (FPDF_WIDESTRING)bsSubject.GetBuffer(bsSubject.GetLength());
970 FPDF_WIDESTRING pMsg = (FPDF_WIDESTRING)bsMsg.GetBuffer(bsMsg.GetLength());
971 pFormFillEnv->EmailTo(pFileHandler, pTo, pSubject, pCC, pBcc, pMsg);
972 bsTo.ReleaseBuffer(bsTo.GetStringLength());
973 bsCC.ReleaseBuffer(bsCC.GetStringLength());
974 bsBcc.ReleaseBuffer(bsBcc.GetStringLength());
975 bsSubject.ReleaseBuffer(bsSubject.GetStringLength());
976 bsMsg.ReleaseBuffer(bsMsg.GetStringLength());
977 } else {
978 // HTTP or FTP
979 WideString ws;
980 ByteString bs = csURL.UTF16LE_Encode();
981 int len = bs.GetLength();
982 pFormFillEnv->UploadTo(pFileHandler, fileFlag,
983 (FPDF_WIDESTRING)bs.GetBuffer(len));
984 bs.ReleaseBuffer(len);
985 }
986 return true;
987 }
988
SetGlobalProperty(CXFA_FFDoc * hDoc,const ByteStringView & szPropName,CFXJSE_Value * pValue)989 bool CPDFXFA_DocEnvironment::SetGlobalProperty(CXFA_FFDoc* hDoc,
990 const ByteStringView& szPropName,
991 CFXJSE_Value* pValue) {
992 if (hDoc != m_pContext->GetXFADoc())
993 return false;
994 if (!m_pContext->GetFormFillEnv() ||
995 !m_pContext->GetFormFillEnv()->GetJSRuntime()) {
996 return false;
997 }
998 CPDFSDK_FormFillEnvironment* pFormFillEnv = m_pContext->GetFormFillEnv();
999 IJS_EventContext* pContext = pFormFillEnv->GetJSRuntime()->NewEventContext();
1000 bool bRet = pFormFillEnv->GetJSRuntime()->SetValueByName(szPropName, pValue);
1001 pFormFillEnv->GetJSRuntime()->ReleaseEventContext(pContext);
1002 return bRet;
1003 }
1004
GetGlobalProperty(CXFA_FFDoc * hDoc,const ByteStringView & szPropName,CFXJSE_Value * pValue)1005 bool CPDFXFA_DocEnvironment::GetGlobalProperty(CXFA_FFDoc* hDoc,
1006 const ByteStringView& szPropName,
1007 CFXJSE_Value* pValue) {
1008 if (hDoc != m_pContext->GetXFADoc())
1009 return false;
1010 if (!m_pContext->GetFormFillEnv() ||
1011 !m_pContext->GetFormFillEnv()->GetJSRuntime()) {
1012 return false;
1013 }
1014 CPDFSDK_FormFillEnvironment* pFormFillEnv = m_pContext->GetFormFillEnv();
1015 IJS_EventContext* pContext = pFormFillEnv->GetJSRuntime()->NewEventContext();
1016 bool bRet = pFormFillEnv->GetJSRuntime()->GetValueByName(szPropName, pValue);
1017 pFormFillEnv->GetJSRuntime()->ReleaseEventContext(pContext);
1018 return bRet;
1019 }
1020