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