• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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