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