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(), 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 =
554 m_pContext->GetFormFillEnv()->GetPageViewAtIndex(i);
555 if (!pPageView)
556 continue;
557
558 ObservedPtr<CPDFSDK_Annot> pAnnot(pPageView->GetAnnotByXFAWidget(hWidget));
559 if (pAnnot) {
560 m_pContext->GetFormFillEnv()->SetFocusAnnot(&pAnnot);
561 break;
562 }
563 }
564 }
565
Print(CXFA_FFDoc * hDoc,int32_t nStartPage,int32_t nEndPage,uint32_t dwOptions)566 void CPDFXFA_DocEnvironment::Print(CXFA_FFDoc* hDoc,
567 int32_t nStartPage,
568 int32_t nEndPage,
569 uint32_t dwOptions) {
570 if (hDoc != m_pContext->GetXFADoc())
571 return;
572
573 CPDFSDK_FormFillEnvironment* pFormFillEnv = m_pContext->GetFormFillEnv();
574 if (!pFormFillEnv || !pFormFillEnv->GetFormFillInfo() ||
575 !pFormFillEnv->GetFormFillInfo()->m_pJsPlatform ||
576 !pFormFillEnv->GetFormFillInfo()->m_pJsPlatform->Doc_print) {
577 return;
578 }
579
580 pFormFillEnv->GetFormFillInfo()->m_pJsPlatform->Doc_print(
581 pFormFillEnv->GetFormFillInfo()->m_pJsPlatform,
582 dwOptions & XFA_PRINTOPT_ShowDialog, nStartPage, nEndPage,
583 dwOptions & XFA_PRINTOPT_CanCancel, dwOptions & XFA_PRINTOPT_ShrinkPage,
584 dwOptions & XFA_PRINTOPT_AsImage, dwOptions & XFA_PRINTOPT_ReverseOrder,
585 dwOptions & XFA_PRINTOPT_PrintAnnot);
586 }
587
GetHighlightColor(CXFA_FFDoc * hDoc)588 FX_ARGB CPDFXFA_DocEnvironment::GetHighlightColor(CXFA_FFDoc* hDoc) {
589 if (hDoc != m_pContext->GetXFADoc() || !m_pContext->GetFormFillEnv())
590 return 0;
591
592 CPDFSDK_InteractiveForm* pForm =
593 m_pContext->GetFormFillEnv()->GetInteractiveForm();
594 return AlphaAndColorRefToArgb(pForm->GetHighlightAlpha(),
595 pForm->GetHighlightColor(FormFieldType::kXFA));
596 }
597
GetIJSRuntime(CXFA_FFDoc * hDoc) const598 IJS_Runtime* CPDFXFA_DocEnvironment::GetIJSRuntime(CXFA_FFDoc* hDoc) const {
599 if (hDoc != m_pContext->GetXFADoc())
600 return nullptr;
601
602 CPDFSDK_FormFillEnvironment* pFormFillEnv = m_pContext->GetFormFillEnv();
603 return pFormFillEnv ? pFormFillEnv->GetIJSRuntime() : nullptr;
604 }
605
OpenLinkedFile(CXFA_FFDoc * hDoc,const WideString & wsLink)606 RetainPtr<IFX_SeekableReadStream> CPDFXFA_DocEnvironment::OpenLinkedFile(
607 CXFA_FFDoc* hDoc,
608 const WideString& wsLink) {
609 CPDFSDK_FormFillEnvironment* pFormFillEnv = m_pContext->GetFormFillEnv();
610 if (!pFormFillEnv)
611 return nullptr;
612
613 ByteString bs = wsLink.ToUTF16LE();
614 FPDF_FILEHANDLER* pFileHandler =
615 pFormFillEnv->OpenFile(0, AsFPDFWideString(&bs), "rb");
616 if (!pFileHandler)
617 return nullptr;
618
619 return MakeSeekableStream(pFileHandler);
620 }
621
622 #ifdef PDF_XFA_ELEMENT_SUBMIT_ENABLED
Submit(CXFA_FFDoc * hDoc,CXFA_Submit * submit)623 bool CPDFXFA_DocEnvironment::Submit(CXFA_FFDoc* hDoc, CXFA_Submit* submit) {
624 if (!NotifySubmit(true) || !m_pContext->GetXFADocView())
625 return false;
626
627 m_pContext->GetXFADocView()->UpdateDocView();
628 bool ret = SubmitInternal(hDoc, submit);
629 NotifySubmit(false);
630 return ret;
631 }
632
MailToInfo(WideString & csURL,WideString & csToAddress,WideString & csCCAddress,WideString & csBCCAddress,WideString & csSubject,WideString & csMsg)633 bool CPDFXFA_DocEnvironment::MailToInfo(WideString& csURL,
634 WideString& csToAddress,
635 WideString& csCCAddress,
636 WideString& csBCCAddress,
637 WideString& csSubject,
638 WideString& csMsg) {
639 WideString srcURL = csURL;
640 srcURL.TrimLeft();
641 if (srcURL.Left(7).CompareNoCase(L"mailto:") != 0)
642 return false;
643
644 auto pos = srcURL.Find(L'?');
645
646 {
647 WideString tmp;
648 if (!pos.has_value()) {
649 pos = srcURL.Find(L'@');
650 if (!pos.has_value())
651 return false;
652
653 tmp = srcURL.Right(csURL.GetLength() - 7);
654 } else {
655 tmp = srcURL.Left(pos.value());
656 tmp = tmp.Right(tmp.GetLength() - 7);
657 }
658 tmp.Trim();
659 csToAddress = std::move(tmp);
660 }
661
662 srcURL = srcURL.Right(srcURL.GetLength() - (pos.value() + 1));
663 while (!srcURL.IsEmpty()) {
664 srcURL.Trim();
665 pos = srcURL.Find(L'&');
666 WideString tmp = (!pos.has_value()) ? srcURL : srcURL.Left(pos.value());
667 tmp.Trim();
668 if (tmp.GetLength() >= 3 && tmp.Left(3).CompareNoCase(L"cc=") == 0) {
669 tmp = tmp.Right(tmp.GetLength() - 3);
670 if (!csCCAddress.IsEmpty())
671 csCCAddress += L';';
672 csCCAddress += tmp;
673 } else if (tmp.GetLength() >= 4 &&
674 tmp.Left(4).CompareNoCase(L"bcc=") == 0) {
675 tmp = tmp.Right(tmp.GetLength() - 4);
676 if (!csBCCAddress.IsEmpty())
677 csBCCAddress += L';';
678 csBCCAddress += tmp;
679 } else if (tmp.GetLength() >= 8 &&
680 tmp.Left(8).CompareNoCase(L"subject=") == 0) {
681 tmp = tmp.Right(tmp.GetLength() - 8);
682 csSubject += tmp;
683 } else if (tmp.GetLength() >= 5 &&
684 tmp.Left(5).CompareNoCase(L"body=") == 0) {
685 tmp = tmp.Right(tmp.GetLength() - 5);
686 csMsg += tmp;
687 }
688 srcURL = pos.has_value()
689 ? srcURL.Right(csURL.GetLength() - (pos.value() + 1))
690 : WideString();
691 }
692 csToAddress.Replace(L",", L";");
693 csCCAddress.Replace(L",", L";");
694 csBCCAddress.Replace(L",", L";");
695 return true;
696 }
697
ExportSubmitFile(FPDF_FILEHANDLER * pFileHandler,int fileType,FPDF_DWORD encodeType,FPDF_DWORD flag)698 bool CPDFXFA_DocEnvironment::ExportSubmitFile(FPDF_FILEHANDLER* pFileHandler,
699 int fileType,
700 FPDF_DWORD encodeType,
701 FPDF_DWORD flag) {
702 if (!m_pContext->GetXFADocView())
703 return false;
704
705 CPDFSDK_FormFillEnvironment* pFormFillEnv = m_pContext->GetFormFillEnv();
706 if (!pFormFillEnv)
707 return false;
708
709 CXFA_FFDoc* ffdoc = m_pContext->GetXFADocView()->GetDoc();
710 RetainPtr<IFX_SeekableStream> fileStream = MakeSeekableStream(pFileHandler);
711 if (fileType == FXFA_SAVEAS_XML) {
712 fileStream->WriteString("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n");
713 ffdoc->SavePackage(
714 ToNode(ffdoc->GetXFADoc()->GetXFAObject(XFA_HASHCODE_Data)),
715 fileStream);
716 return true;
717 }
718
719 if (fileType != FXFA_SAVEAS_XDP)
720 return true;
721
722 if (!flag) {
723 flag = FXFA_CONFIG | FXFA_TEMPLATE | FXFA_LOCALESET | FXFA_DATASETS |
724 FXFA_XMPMETA | FXFA_XFDF | FXFA_FORM;
725 }
726 if (!m_pContext->GetPDFDoc()) {
727 fileStream->Flush();
728 return false;
729 }
730
731 const CPDF_Dictionary* pRoot = m_pContext->GetPDFDoc()->GetRoot();
732 if (!pRoot) {
733 fileStream->Flush();
734 return false;
735 }
736
737 const CPDF_Dictionary* pAcroForm = pRoot->GetDictFor("AcroForm");
738 if (!pAcroForm) {
739 fileStream->Flush();
740 return false;
741 }
742
743 const CPDF_Array* pArray = ToArray(pAcroForm->GetObjectFor("XFA"));
744 if (!pArray) {
745 fileStream->Flush();
746 return false;
747 }
748
749 for (size_t i = 1; i < pArray->size(); i += 2) {
750 const CPDF_Object* pPDFObj = pArray->GetObjectAt(i);
751 const CPDF_Object* pPrePDFObj = pArray->GetObjectAt(i - 1);
752 if (!pPrePDFObj->IsString())
753 continue;
754 if (!pPDFObj->IsReference())
755 continue;
756
757 const CPDF_Object* pDirectObj = pPDFObj->GetDirect();
758 if (!pDirectObj->IsStream())
759 continue;
760 ByteString bsType = pPrePDFObj->GetString();
761 if (bsType == "config" && !(flag & FXFA_CONFIG))
762 continue;
763 if (bsType == "template" && !(flag & FXFA_TEMPLATE))
764 continue;
765 if (bsType == "localeSet" && !(flag & FXFA_LOCALESET))
766 continue;
767 if (bsType == "datasets" && !(flag & FXFA_DATASETS))
768 continue;
769 if (bsType == "xmpmeta" && !(flag & FXFA_XMPMETA))
770 continue;
771 if (bsType == "xfdf" && !(flag & FXFA_XFDF))
772 continue;
773 if (bsType == "form" && !(flag & FXFA_FORM))
774 continue;
775
776 if (bsType == "form") {
777 ffdoc->SavePackage(
778 ToNode(ffdoc->GetXFADoc()->GetXFAObject(XFA_HASHCODE_Form)),
779 fileStream);
780 } else if (pPrePDFObj->GetString() == "datasets") {
781 ffdoc->SavePackage(
782 ToNode(ffdoc->GetXFADoc()->GetXFAObject(XFA_HASHCODE_Datasets)),
783 fileStream);
784 }
785 }
786 return true;
787 }
788
ToXFAContentFlags(WideString csSrcContent,FPDF_DWORD & flag)789 void CPDFXFA_DocEnvironment::ToXFAContentFlags(WideString csSrcContent,
790 FPDF_DWORD& flag) {
791 if (csSrcContent.Contains(L" config "))
792 flag |= FXFA_CONFIG;
793 if (csSrcContent.Contains(L" template "))
794 flag |= FXFA_TEMPLATE;
795 if (csSrcContent.Contains(L" localeSet "))
796 flag |= FXFA_LOCALESET;
797 if (csSrcContent.Contains(L" datasets "))
798 flag |= FXFA_DATASETS;
799 if (csSrcContent.Contains(L" xmpmeta "))
800 flag |= FXFA_XMPMETA;
801 if (csSrcContent.Contains(L" xfdf "))
802 flag |= FXFA_XFDF;
803 if (csSrcContent.Contains(L" form "))
804 flag |= FXFA_FORM;
805 if (flag == 0) {
806 flag = FXFA_CONFIG | FXFA_TEMPLATE | FXFA_LOCALESET | FXFA_DATASETS |
807 FXFA_XMPMETA | FXFA_XFDF | FXFA_FORM;
808 }
809 }
810
OnBeforeNotifySubmit()811 bool CPDFXFA_DocEnvironment::OnBeforeNotifySubmit() {
812 if (!m_pContext->ContainsXFAForm())
813 return true;
814
815 CXFA_FFDocView* docView = m_pContext->GetXFADocView();
816 if (!docView)
817 return true;
818
819 CXFA_FFWidgetHandler* pWidgetHandler = docView->GetWidgetHandler();
820 if (!pWidgetHandler)
821 return true;
822
823 auto it = docView->CreateReadyNodeIterator();
824 if (it) {
825 CXFA_EventParam Param;
826 Param.m_eType = XFA_EVENT_PreSubmit;
827 while (CXFA_Node* pNode = it->MoveToNext())
828 pWidgetHandler->ProcessEvent(pNode, &Param);
829 }
830
831 it = docView->CreateReadyNodeIterator();
832 if (!it)
833 return true;
834
835 (void)it->MoveToNext();
836 CXFA_Node* pNode = it->MoveToNext();
837
838 while (pNode) {
839 if (pNode->ProcessValidate(docView, -1) == XFA_EventError::kError) {
840 CPDFSDK_FormFillEnvironment* pFormFillEnv = m_pContext->GetFormFillEnv();
841 if (!pFormFillEnv)
842 return false;
843
844 pFormFillEnv->JS_appAlert(WideString::FromDefANSI(IDS_XFA_Validate_Input),
845 WideString(), JSPLATFORM_ALERT_BUTTON_OK,
846 JSPLATFORM_ALERT_ICON_WARNING);
847 return false;
848 }
849 pNode = it->MoveToNext();
850 }
851
852 docView->UpdateDocView();
853 return true;
854 }
855
OnAfterNotifySubmit()856 void CPDFXFA_DocEnvironment::OnAfterNotifySubmit() {
857 if (!m_pContext->ContainsXFAForm())
858 return;
859
860 if (!m_pContext->GetXFADocView())
861 return;
862
863 CXFA_FFWidgetHandler* pWidgetHandler =
864 m_pContext->GetXFADocView()->GetWidgetHandler();
865 if (!pWidgetHandler)
866 return;
867
868 auto it = m_pContext->GetXFADocView()->CreateReadyNodeIterator();
869 if (!it)
870 return;
871
872 CXFA_EventParam Param;
873 Param.m_eType = XFA_EVENT_PostSubmit;
874 CXFA_Node* pNode = it->MoveToNext();
875 while (pNode) {
876 pWidgetHandler->ProcessEvent(pNode, &Param);
877 pNode = it->MoveToNext();
878 }
879 m_pContext->GetXFADocView()->UpdateDocView();
880 }
881
NotifySubmit(bool bPrevOrPost)882 bool CPDFXFA_DocEnvironment::NotifySubmit(bool bPrevOrPost) {
883 if (bPrevOrPost)
884 return OnBeforeNotifySubmit();
885
886 OnAfterNotifySubmit();
887 return true;
888 }
889
SubmitInternal(CXFA_FFDoc * hDoc,CXFA_Submit * submit)890 bool CPDFXFA_DocEnvironment::SubmitInternal(CXFA_FFDoc* hDoc,
891 CXFA_Submit* submit) {
892 CPDFSDK_FormFillEnvironment* pFormFillEnv = m_pContext->GetFormFillEnv();
893 if (!pFormFillEnv)
894 return false;
895
896 WideString csURL = submit->GetSubmitTarget();
897 if (csURL.IsEmpty()) {
898 pFormFillEnv->JS_appAlert(WideString::FromDefANSI("Submit cancelled."),
899 WideString(), JSPLATFORM_ALERT_BUTTON_OK,
900 JSPLATFORM_ALERT_ICON_ASTERISK);
901 return false;
902 }
903
904 FPDF_FILEHANDLER* pFileHandler = nullptr;
905 int fileFlag = -1;
906 switch (submit->GetSubmitFormat()) {
907 case XFA_AttributeValue::Xdp: {
908 WideString csContent = submit->GetSubmitXDPContent();
909 csContent.Trim();
910
911 WideString space = WideString::FromDefANSI(" ");
912 csContent = space + csContent + space;
913 FPDF_DWORD flag = 0;
914 if (submit->IsSubmitEmbedPDF())
915 flag |= FXFA_PDF;
916
917 ToXFAContentFlags(csContent, flag);
918 pFileHandler = pFormFillEnv->OpenFile(FXFA_SAVEAS_XDP, nullptr, "wb");
919 fileFlag = FXFA_SAVEAS_XDP;
920 ExportSubmitFile(pFileHandler, FXFA_SAVEAS_XDP, 0, flag);
921 break;
922 }
923 case XFA_AttributeValue::Xml:
924 pFileHandler = pFormFillEnv->OpenFile(FXFA_SAVEAS_XML, nullptr, "wb");
925 fileFlag = FXFA_SAVEAS_XML;
926 ExportSubmitFile(pFileHandler, FXFA_SAVEAS_XML, 0, FXFA_XFA_ALL);
927 break;
928 case XFA_AttributeValue::Pdf:
929 break;
930 case XFA_AttributeValue::Urlencoded:
931 pFileHandler = pFormFillEnv->OpenFile(FXFA_SAVEAS_XML, nullptr, "wb");
932 fileFlag = FXFA_SAVEAS_XML;
933 ExportSubmitFile(pFileHandler, FXFA_SAVEAS_XML, 0, FXFA_XFA_ALL);
934 break;
935 default:
936 return false;
937 }
938 if (!pFileHandler)
939 return false;
940
941 if (csURL.Left(7).CompareNoCase(L"mailto:") == 0) {
942 WideString csToAddress;
943 WideString csCCAddress;
944 WideString csBCCAddress;
945 WideString csSubject;
946 WideString csMsg;
947 if (!MailToInfo(csURL, csToAddress, csCCAddress, csBCCAddress, csSubject,
948 csMsg)) {
949 return false;
950 }
951 ByteString bsTo = WideString(csToAddress).ToUTF16LE();
952 ByteString bsCC = WideString(csCCAddress).ToUTF16LE();
953 ByteString bsBcc = WideString(csBCCAddress).ToUTF16LE();
954 ByteString bsSubject = WideString(csSubject).ToUTF16LE();
955 ByteString bsMsg = WideString(csMsg).ToUTF16LE();
956 pFormFillEnv->EmailTo(pFileHandler, AsFPDFWideString(&bsTo),
957 AsFPDFWideString(&bsSubject), AsFPDFWideString(&bsCC),
958 AsFPDFWideString(&bsBcc), AsFPDFWideString(&bsMsg));
959 return true;
960 }
961
962 // HTTP or FTP
963 ByteString bs = csURL.ToUTF16LE();
964 pFormFillEnv->UploadTo(pFileHandler, fileFlag, AsFPDFWideString(&bs));
965 return true;
966 }
967 #endif // PDF_XFA_ELEMENT_SUBMIT_ENABLED
968