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
cpdf_interactiveform.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 "core/fpdfdoc/cpdf_interactiveform.h"
8
9#include <optional>
10#include <type_traits>
11#include <utility>
12#include <vector>
13
14#include "build/build_config.h"
15#include "constants/form_fields.h"
16#include "constants/form_flags.h"
17#include "constants/stream_dict_common.h"
18#include "core/fpdfapi/font/cpdf_font.h"
19#include "core/fpdfapi/font/cpdf_fontencoding.h"
20#include "core/fpdfapi/page/cpdf_docpagedata.h"
21#include "core/fpdfapi/page/cpdf_page.h"
22#include "core/fpdfapi/parser/cfdf_document.h"
23#include "core/fpdfapi/parser/cpdf_array.h"
24#include "core/fpdfapi/parser/cpdf_dictionary.h"
25#include "core/fpdfapi/parser/cpdf_document.h"
26#include "core/fpdfapi/parser/cpdf_name.h"
27#include "core/fpdfapi/parser/cpdf_reference.h"
28#include "core/fpdfapi/parser/cpdf_stream.h"
29#include "core/fpdfapi/parser/cpdf_string.h"
30#include "core/fpdfapi/parser/fpdf_parser_utility.h"
31#include "core/fpdfdoc/cpdf_filespec.h"
32#include "core/fpdfdoc/cpdf_formcontrol.h"
33#include "core/fxcrt/check.h"
34#include "core/fxcrt/compiler_specific.h"
35#include "core/fxcrt/containers/contains.h"
36#include "core/fxcrt/fx_codepage.h"
37#include "core/fxcrt/fx_memcpy_wrappers.h"
38#include "core/fxcrt/numerics/safe_conversions.h"
39#include "core/fxcrt/stl_util.h"
40#include "core/fxge/fx_font.h"
41
42#if BUILDFLAG(IS_WIN)
43#include "core/fxcrt/win/win_util.h"
44#endif
45
46namespace {
47
48const int nMaxRecursion = 32;
49
50#if BUILDFLAG(IS_WIN)
51struct PDF_FONTDATA {
52 bool bFind;
53 LOGFONTA lf;
54};
55
56int CALLBACK EnumFontFamExProc(ENUMLOGFONTEXA* lpelfe,
57 NEWTEXTMETRICEX* lpntme,
58 DWORD FontType,
59 LPARAM lParam) {
60 if (FontType != 0x004 || strchr(lpelfe->elfLogFont.lfFaceName, '@'))
61 return 1;
62
63 PDF_FONTDATA* pData = (PDF_FONTDATA*)lParam;
64 pData->lf = lpelfe->elfLogFont;
65 pData->bFind = true;
66 return 0;
67}
68
69bool RetrieveSpecificFont(FX_Charset charSet,
70 LPCSTR pcsFontName,
71 LOGFONTA& lf) {
72 lf = {}; // Aggregate initialization, not construction.
73 static_assert(std::is_aggregate_v<std::remove_reference_t<decltype(lf)>>);
74 lf.lfCharSet = static_cast<int>(charSet);
75 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
76 if (pcsFontName) {
77 // TODO(dsinclair): Should this be strncpy?
78 // NOLINTNEXTLINE(runtime/printf)
79 strcpy(lf.lfFaceName, pcsFontName);
80 }
81
82 PDF_FONTDATA fd = {}; // Aggregate initialization, not construction.
83 static_assert(std::is_aggregate_v<decltype(fd)>);
84 HDC hDC = ::GetDC(nullptr);
85 EnumFontFamiliesExA(hDC, &lf, (FONTENUMPROCA)EnumFontFamExProc, (LPARAM)&fd,
86 0);
87 ::ReleaseDC(nullptr, hDC);
88 if (fd.bFind) {
89 UNSAFE_TODO(FXSYS_memcpy(&lf, &fd.lf, sizeof(LOGFONTA)));
90 }
91 return fd.bFind;
92}
93#endif // BUILDFLAG(IS_WIN)
94
95ByteString GetNativeFontName(FX_Charset charSet, void* pLogFont) {
96 ByteString csFontName;
97#if BUILDFLAG(IS_WIN)
98 LOGFONTA lf = {};
99 if (charSet == FX_Charset::kANSI) {
100 return CFX_Font::kDefaultAnsiFontName;
101 }
102
103 if (!pdfium::IsUser32AndGdi32Available()) {
104 // Without GDI32 and User32, GetDC / EnumFontFamiliesExW / ReleaseDC all
105 // fail, which is called by RetrieveSpecificFont. We won't be able to look
106 // up native fonts without GDI.
107 return ByteString();
108 }
109
110 bool bRet = false;
111 const ByteString default_font_name =
112 CFX_Font::GetDefaultFontNameByCharset(charSet);
113 if (!default_font_name.IsEmpty())
114 bRet = RetrieveSpecificFont(charSet, default_font_name.c_str(), lf);
115 if (!bRet) {
116 bRet =
117 RetrieveSpecificFont(charSet, CFX_Font::kUniversalDefaultFontName, lf);
118 }
119 if (!bRet)
120 bRet = RetrieveSpecificFont(charSet, "Microsoft Sans Serif", lf);
121 if (!bRet)
122 bRet = RetrieveSpecificFont(charSet, nullptr, lf);
123 if (bRet) {
124 if (pLogFont) {
125 UNSAFE_TODO(FXSYS_memcpy(pLogFont, &lf, sizeof(LOGFONTA)));
126 }
127 csFontName = lf.lfFaceName;
128 }
129#endif
130 return csFontName;
131}
132
133ByteString GenerateNewFontResourceName(const CPDF_Dictionary* pResDict,
134 const ByteString& csPrefix) {
135 static const char kDummyFontName[] = "ZiTi";
136 ByteString csStr = csPrefix;
137 if (csStr.IsEmpty())
138 csStr = kDummyFontName;
139
140 const size_t szCount = csStr.GetLength();
141 size_t m = 0;
142 ByteString csTmp;
143 while (m < strlen(kDummyFontName) && m < szCount)
144 csTmp += csStr[m++];
145 while (m < strlen(kDummyFontName)) {
146 csTmp += '0' + m % 10;
147 m++;
148 }
149
150 RetainPtr<const CPDF_Dictionary> pDict = pResDict->GetDictFor("Font");
151 DCHECK(pDict);
152
153 int num = 0;
154 ByteString bsNum;
155 while (true) {
156 ByteString csKey = csTmp + bsNum;
157 if (!pDict->KeyExist(csKey))
158 return csKey;
159
160 if (m < szCount)
161 csTmp += csStr[m++];
162 else
164 m++;
165 }
166}
167
168RetainPtr<CPDF_Font> AddStandardFont(CPDF_Document* pDocument) {
169 auto* pPageData = CPDF_DocPageData::FromDocument(pDocument);
170 static const CPDF_FontEncoding encoding(FontEncoding::kWinAnsi);
171 return pPageData->AddStandardFont(CFX_Font::kDefaultAnsiFontName, &encoding);
172}
173
174RetainPtr<CPDF_Font> AddNativeFont(FX_Charset charSet,
175 CPDF_Document* pDocument) {
176 DCHECK(pDocument);
177
178#if BUILDFLAG(IS_WIN)
179 LOGFONTA lf;
180 ByteString csFontName = GetNativeFontName(charSet, &lf);
181 if (!csFontName.IsEmpty()) {
182 if (csFontName == CFX_Font::kDefaultAnsiFontName)
183 return AddStandardFont(pDocument);
184 return CPDF_DocPageData::FromDocument(pDocument)->AddWindowsFont(&lf);
185 }
186#endif
187 return nullptr;
188}
189
190bool FindFont(const CPDF_Dictionary* pFormDict,
191 const CPDF_Font* pFont,
192 ByteString* csNameTag) {
193 RetainPtr<const CPDF_Dictionary> pDR = pFormDict->GetDictFor("DR");
194 if (!pDR)
195 return false;
196
197 RetainPtr<const CPDF_Dictionary> pFonts = pDR->GetDictFor("Font");
198 // TODO(tsepez): this eventually locks the dict, pass locker instead.
199 if (!ValidateFontResourceDict(pFonts.Get()))
200 return false;
201
202 CPDF_DictionaryLocker locker(std::move(pFonts));
203 for (const auto& it : locker) {
204 const ByteString& csKey = it.first;
205 RetainPtr<const CPDF_Dictionary> pElement =
206 ToDictionary(it.second->GetDirect());
207 if (!ValidateDictType(pElement.Get(), "Font"))
208 continue;
209 if (pFont->FontDictIs(pElement)) {
210 *csNameTag = csKey;
211 return true;
212 }
213 }
214 return false;
215}
216
217bool FindFontFromDoc(const CPDF_Dictionary* pFormDict,
218 CPDF_Document* pDocument,
219 ByteString csFontName,
220 RetainPtr<CPDF_Font>& pFont,
221 ByteString* csNameTag) {
222 if (csFontName.IsEmpty())
223 return false;
224
225 RetainPtr<const CPDF_Dictionary> pDR = pFormDict->GetDictFor("DR");
226 if (!pDR)
227 return false;
228
229 RetainPtr<const CPDF_Dictionary> pFonts = pDR->GetDictFor("Font");
230 if (!ValidateFontResourceDict(pFonts.Get()))
231 return false;
232
233 csFontName.Remove(' ');
234 CPDF_DictionaryLocker locker(pFonts);
235 for (const auto& it : locker) {
236 const ByteString& csKey = it.first;
237 RetainPtr<CPDF_Dictionary> pElement =
238 ToDictionary(it.second->GetMutableDirect());
239 if (!ValidateDictType(pElement.Get(), "Font"))
240 continue;
241
242 auto* pData = CPDF_DocPageData::FromDocument(pDocument);
243 pFont = pData->GetFont(std::move(pElement));
244 if (!pFont)
245 continue;
246
247 ByteString csBaseFont = pFont->GetBaseFontName();
248 csBaseFont.Remove(' ');
249 if (csBaseFont == csFontName) {
250 *csNameTag = csKey;
251 return true;
252 }
253 }
254 return false;
255}
256
257void AddFont(CPDF_Dictionary* pFormDict,
258 CPDF_Document* pDocument,
259 const RetainPtr<CPDF_Font>& pFont,
260 ByteString* csNameTag) {
261 DCHECK(pFormDict);
262 DCHECK(pFont);
263
264 ByteString csTag;
265 if (FindFont(pFormDict, pFont.Get(), &csTag)) {
266 *csNameTag = std::move(csTag);
267 return;
268 }
269
270 RetainPtr<CPDF_Dictionary> pDR = pFormDict->GetOrCreateDictFor("DR");
271 RetainPtr<CPDF_Dictionary> pFonts = pDR->GetOrCreateDictFor("Font");
272
273 if (csNameTag->IsEmpty())
274 *csNameTag = pFont->GetBaseFontName();
275
276 csNameTag->Remove(' ');
277 *csNameTag = GenerateNewFontResourceName(pDR.Get(), *csNameTag);
278 pFonts->SetNewFor<CPDF_Reference>(*csNameTag, pDocument,
279 pFont->GetFontDictObjNum());
280}
281
282FX_Charset GetNativeCharSet() {
284}
285
286RetainPtr<CPDF_Dictionary> InitDict(CPDF_Document* pDocument) {
287 auto pFormDict = pDocument->NewIndirect<CPDF_Dictionary>();
288 pDocument->GetMutableRoot()->SetNewFor<CPDF_Reference>(
289 "AcroForm", pDocument, pFormDict->GetObjNum());
290
291 ByteString csBaseName;
292 FX_Charset charSet = GetNativeCharSet();
293 RetainPtr<CPDF_Font> pFont = AddStandardFont(pDocument);
294 if (pFont) {
295 AddFont(pFormDict.Get(), pDocument, pFont, &csBaseName);
296 }
297 if (charSet != FX_Charset::kANSI) {
298 ByteString csFontName = GetNativeFontName(charSet, nullptr);
299 if (!pFont || csFontName != CFX_Font::kDefaultAnsiFontName) {
300 pFont = AddNativeFont(charSet, pDocument);
301 if (pFont) {
302 csBaseName.clear();
303 AddFont(pFormDict.Get(), pDocument, pFont, &csBaseName);
304 }
305 }
306 }
307 ByteString csDA;
308 if (pFont)
309 csDA = "/" + PDF_NameEncode(csBaseName) + " 0 Tf ";
310 csDA += "0 g";
311 pFormDict->SetNewFor<CPDF_String>("DA", csDA);
312 return pFormDict;
313}
314
315RetainPtr<CPDF_Font> GetNativeFont(const CPDF_Dictionary* pFormDict,
316 CPDF_Document* pDocument,
317 FX_Charset charSet,
318 ByteString* csNameTag) {
319 RetainPtr<const CPDF_Dictionary> pDR = pFormDict->GetDictFor("DR");
320 if (!pDR)
321 return nullptr;
322
323 RetainPtr<const CPDF_Dictionary> pFonts = pDR->GetDictFor("Font");
324 if (!ValidateFontResourceDict(pFonts.Get()))
325 return nullptr;
326
327 CPDF_DictionaryLocker locker(pFonts);
328 for (const auto& it : locker) {
329 const ByteString& csKey = it.first;
330 RetainPtr<CPDF_Dictionary> pElement =
331 ToDictionary(it.second->GetMutableDirect());
332 if (!ValidateDictType(pElement.Get(), "Font"))
333 continue;
334
335 auto* pData = CPDF_DocPageData::FromDocument(pDocument);
336 RetainPtr<CPDF_Font> pFind = pData->GetFont(std::move(pElement));
337 if (!pFind)
338 continue;
339
340 auto maybe_charset = pFind->GetSubstFontCharset();
341 if (maybe_charset.has_value() && maybe_charset.value() == charSet) {
342 *csNameTag = csKey;
343 return pFind;
344 }
345 }
346 return nullptr;
347}
348
349class CFieldNameExtractor {
350 public:
351 explicit CFieldNameExtractor(const WideString& full_name)
352 : m_FullName(full_name) {}
353
354 WideStringView GetNext() {
355 size_t start_pos = m_iCur;
356 while (m_iCur < m_FullName.GetLength() && m_FullName[m_iCur] != L'.')
357 ++m_iCur;
358
359 size_t length = m_iCur - start_pos;
360 if (m_iCur < m_FullName.GetLength() && m_FullName[m_iCur] == L'.')
361 ++m_iCur;
362
363 return m_FullName.AsStringView().Substr(start_pos, length);
364 }
365
366 protected:
367 const WideString m_FullName;
368 size_t m_iCur = 0;
369};
370
371} // namespace
372
374 public:
375 class Node {
376 public:
377 Node() : m_level(0) {}
378 Node(const WideString& short_name, int level)
379 : m_ShortName(short_name), m_level(level) {}
380 ~Node() = default;
381
382 void AddChildNode(std::unique_ptr<Node> pNode) {
383 m_Children.push_back(std::move(pNode));
384 }
385
386 size_t GetChildrenCount() const { return m_Children.size(); }
387
388 Node* GetChildAt(size_t i) { return m_Children[i].get(); }
389 const Node* GetChildAt(size_t i) const { return m_Children[i].get(); }
390
392 size_t nFieldsToGo = index;
393 return GetFieldInternal(&nFieldsToGo);
394 }
395
396 size_t CountFields() const { return CountFieldsInternal(); }
397
398 void SetField(std::unique_ptr<CPDF_FormField> pField) {
399 m_pField = std::move(pField);
400 }
401
402 CPDF_FormField* GetField() const { return m_pField.get(); }
403 WideString GetShortName() const { return m_ShortName; }
404 int GetLevel() const { return m_level; }
405
406 private:
407 CPDF_FormField* GetFieldInternal(size_t* pFieldsToGo) {
408 if (m_pField) {
409 if (*pFieldsToGo == 0)
410 return m_pField.get();
411
412 --*pFieldsToGo;
413 }
414 for (size_t i = 0; i < GetChildrenCount(); ++i) {
415 CPDF_FormField* pField = GetChildAt(i)->GetFieldInternal(pFieldsToGo);
416 if (pField)
417 return pField;
418 }
419 return nullptr;
420 }
421
422 size_t CountFieldsInternal() const {
423 size_t count = 0;
424 if (m_pField)
425 ++count;
426
427 for (size_t i = 0; i < GetChildrenCount(); ++i)
428 count += GetChildAt(i)->CountFieldsInternal();
429 return count;
430 }
431
432 std::vector<std::unique_ptr<Node>> m_Children;
433 WideString m_ShortName;
434 std::unique_ptr<CPDF_FormField> m_pField;
435 const int m_level;
436 };
437
440
441 bool SetField(const WideString& full_name,
442 std::unique_ptr<CPDF_FormField> pField);
444
445 Node* GetRoot() { return m_pRoot.get(); }
446 Node* FindNode(const WideString& full_name);
447 Node* AddChild(Node* pParent, const WideString& short_name);
448 Node* Lookup(Node* pParent, WideStringView short_name);
449
450 private:
451 std::unique_ptr<Node> m_pRoot;
452};
453
455
456CFieldTree::~CFieldTree() = default;
457
459 const WideString& short_name) {
460 if (!pParent)
461 return nullptr;
462
463 int level = pParent->GetLevel() + 1;
464 if (level > nMaxRecursion)
465 return nullptr;
466
467 auto pNew = std::make_unique<Node>(short_name, pParent->GetLevel() + 1);
468 Node* pChild = pNew.get();
469 pParent->AddChildNode(std::move(pNew));
470 return pChild;
471}
472
474 if (!pParent)
475 return nullptr;
476
477 for (size_t i = 0; i < pParent->GetChildrenCount(); ++i) {
478 Node* pNode = pParent->GetChildAt(i);
479 if (pNode->GetShortName() == short_name)
480 return pNode;
481 }
482 return nullptr;
483}
484
485bool CFieldTree::SetField(const WideString& full_name,
486 std::unique_ptr<CPDF_FormField> pField) {
487 if (full_name.IsEmpty())
488 return false;
489
490 Node* pNode = GetRoot();
491 Node* pLast = nullptr;
492 CFieldNameExtractor name_extractor(full_name);
493 while (true) {
494 WideStringView name_view = name_extractor.GetNext();
495 if (name_view.IsEmpty())
496 break;
497 pLast = pNode;
498 pNode = Lookup(pLast, name_view);
499 if (pNode)
500 continue;
501 pNode = AddChild(pLast, WideString(name_view));
502 if (!pNode)
503 return false;
504 }
505 if (pNode == GetRoot())
506 return false;
507
508 pNode->SetField(std::move(pField));
509 return true;
510}
511
513 if (full_name.IsEmpty())
514 return nullptr;
515
516 Node* pNode = GetRoot();
517 Node* pLast = nullptr;
518 CFieldNameExtractor name_extractor(full_name);
519 while (pNode) {
520 WideStringView name_view = name_extractor.GetNext();
521 if (name_view.IsEmpty())
522 break;
523 pLast = pNode;
524 pNode = Lookup(pLast, name_view);
525 }
526 return pNode ? pNode->GetField() : nullptr;
527}
528
530 if (full_name.IsEmpty())
531 return nullptr;
532
533 Node* pNode = GetRoot();
534 Node* pLast = nullptr;
535 CFieldNameExtractor name_extractor(full_name);
536 while (pNode) {
537 WideStringView name_view = name_extractor.GetNext();
538 if (name_view.IsEmpty())
539 break;
540 pLast = pNode;
541 pNode = Lookup(pLast, name_view);
542 }
543 return pNode;
544}
545
548 RetainPtr<CPDF_Dictionary> pRoot = m_pDocument->GetMutableRoot();
549 if (!pRoot)
550 return;
551
552 m_pFormDict = pRoot->GetMutableDictFor("AcroForm");
553 if (!m_pFormDict)
554 return;
555
556 RetainPtr<CPDF_Array> pFields = m_pFormDict->GetMutableArrayFor("Fields");
557 if (!pFields)
558 return;
559
560 for (size_t i = 0; i < pFields->size(); ++i)
561 LoadField(pFields->GetMutableDictAt(i), 0);
562}
563
565
566bool CPDF_InteractiveForm::s_bUpdateAP = true;
567
568// static
570 return s_bUpdateAP;
571}
572
573// static
574void CPDF_InteractiveForm::SetUpdateAP(bool bUpdateAP) {
575 s_bUpdateAP = bUpdateAP;
576}
577
578// static
580 CPDF_Document* pDocument,
581 ByteString* csNameTag) {
582 DCHECK(pDocument);
583 DCHECK(csNameTag);
584
585 RetainPtr<CPDF_Dictionary> pFormDict =
586 pDocument->GetMutableRoot()->GetMutableDictFor("AcroForm");
587 if (!pFormDict)
588 pFormDict = InitDict(pDocument);
589
590 FX_Charset charSet = GetNativeCharSet();
591 ByteString csTemp;
592 RetainPtr<CPDF_Font> pFont =
593 GetNativeFont(pFormDict.Get(), pDocument, charSet, &csTemp);
594 if (pFont) {
595 *csNameTag = std::move(csTemp);
596 return pFont;
597 }
598 ByteString csFontName = GetNativeFontName(charSet, nullptr);
599 if (FindFontFromDoc(pFormDict.Get(), pDocument, csFontName, pFont, csNameTag))
600 return pFont;
601
602 pFont = AddNativeFont(charSet, pDocument);
603 if (!pFont)
604 return nullptr;
605
606 AddFont(pFormDict.Get(), pDocument, pFont, csNameTag);
607 return pFont;
608}
609
611 if (csFieldName.IsEmpty())
612 return m_pFieldTree->GetRoot()->CountFields();
613
614 CFieldTree::Node* pNode = m_pFieldTree->FindNode(csFieldName);
615 return pNode ? pNode->CountFields() : 0;
616}
617
619 size_t index,
620 const WideString& csFieldName) const {
621 if (csFieldName.IsEmpty())
622 return m_pFieldTree->GetRoot()->GetFieldAtIndex(index);
623
624 CFieldTree::Node* pNode = m_pFieldTree->FindNode(csFieldName);
625 return pNode ? pNode->GetFieldAtIndex(index) : nullptr;
626}
627
629 const CPDF_Dictionary* pFieldDict) const {
630 if (!pFieldDict)
631 return nullptr;
632
634 return m_pFieldTree->GetField(csWName);
635}
636
638 const CPDF_Page* pPage,
639 const CFX_PointF& point,
640 int* z_order) const {
641 RetainPtr<const CPDF_Array> pAnnotList = pPage->GetAnnotsArray();
642 if (!pAnnotList)
643 return nullptr;
644
645 for (size_t i = pAnnotList->size(); i > 0; --i) {
646 size_t annot_index = i - 1;
647 RetainPtr<const CPDF_Dictionary> pAnnot =
648 pAnnotList->GetDictAt(annot_index);
649 if (!pAnnot)
650 continue;
651
652 const auto it = m_ControlMap.find(pAnnot.Get());
653 if (it == m_ControlMap.end())
654 continue;
655
656 const CPDF_FormControl* pControl = it->second.get();
657 if (!pControl->GetRect().Contains(point))
658 continue;
659
660 if (z_order)
661 *z_order = static_cast<int>(annot_index);
662 return pControl;
663 }
664 return nullptr;
665}
666
668 const CPDF_Dictionary* pWidgetDict) const {
669 const auto it = m_ControlMap.find(pWidgetDict);
670 return it != m_ControlMap.end() ? it->second.get() : nullptr;
671}
672
674 return m_pFormDict && m_pFormDict->GetBooleanFor("NeedAppearances", false);
675}
676
678 if (!m_pFormDict)
679 return 0;
680
681 RetainPtr<const CPDF_Array> pArray = m_pFormDict->GetArrayFor("CO");
682 return pArray ? fxcrt::CollectionSize<int>(*pArray) : 0;
683}
684
686 if (!m_pFormDict || index < 0)
687 return nullptr;
688
689 RetainPtr<const CPDF_Array> pArray = m_pFormDict->GetArrayFor("CO");
690 if (!pArray)
691 return nullptr;
692
693 RetainPtr<const CPDF_Dictionary> pElement =
694 ToDictionary(pArray->GetDirectObjectAt(index));
695 return pElement ? GetFieldByDict(pElement.Get()) : nullptr;
696}
697
699 const CPDF_FormField* pField) {
700 if (!m_pFormDict)
701 return -1;
702
703 RetainPtr<const CPDF_Array> pArray = m_pFormDict->GetArrayFor("CO");
704 if (!pArray)
705 return -1;
706
707 std::optional<size_t> maybe_found = pArray->Find(pField->GetFieldDict());
708 if (!maybe_found.has_value())
709 return -1;
710
711 return pdfium::checked_cast<int>(maybe_found.value());
712}
713
715 ByteString csNameTag) const {
716 ByteString csAlias = PDF_NameDecode(csNameTag.AsStringView());
717 if (!m_pFormDict || csAlias.IsEmpty())
718 return nullptr;
719
720 RetainPtr<CPDF_Dictionary> pDR = m_pFormDict->GetMutableDictFor("DR");
721 if (!pDR)
722 return nullptr;
723
724 RetainPtr<CPDF_Dictionary> pFonts = pDR->GetMutableDictFor("Font");
725 if (!ValidateFontResourceDict(pFonts.Get()))
726 return nullptr;
727
728 RetainPtr<CPDF_Dictionary> pElement = pFonts->GetMutableDictFor(csAlias);
729 if (!ValidateDictType(pElement.Get(), "Font"))
730 return nullptr;
731
732 return GetFontForElement(std::move(pElement));
733}
734
736 RetainPtr<CPDF_Dictionary> pElement) const {
737 auto* pData = CPDF_DocPageData::FromDocument(m_pDocument);
738 return pData->GetFont(std::move(pElement));
739}
740
742 return CPDF_DefaultAppearance(
743 m_pFormDict ? m_pFormDict->GetByteStringFor("DA") : "");
744}
745
747 return m_pFormDict ? m_pFormDict->GetIntegerFor("Q", 0) : 0;
748}
749
750void CPDF_InteractiveForm::ResetForm(pdfium::span<CPDF_FormField*> fields,
751 bool bIncludeOrExclude) {
752 CFieldTree::Node* pRoot = m_pFieldTree->GetRoot();
753 const size_t nCount = pRoot->CountFields();
754 for (size_t i = 0; i < nCount; ++i) {
755 CPDF_FormField* pField = pRoot->GetFieldAtIndex(i);
756 if (!pField)
757 continue;
758
759 if (bIncludeOrExclude == pdfium::Contains(fields, pField))
760 pField->ResetField();
761 }
762 if (m_pFormNotify)
763 m_pFormNotify->AfterFormReset(this);
764}
765
767 ResetForm(/*fields=*/{}, /*bIncludeOrExclude=*/false);
768}
769
772 return m_ControlLists[pdfium::WrapUnowned(pField)];
773}
774
775void CPDF_InteractiveForm::LoadField(RetainPtr<CPDF_Dictionary> pFieldDict,
776 int nLevel) {
777 if (nLevel > nMaxRecursion)
778 return;
779 if (!pFieldDict)
780 return;
781
782 uint32_t dwParentObjNum = pFieldDict->GetObjNum();
783 RetainPtr<CPDF_Array> pKids =
784 pFieldDict->GetMutableArrayFor(pdfium::form_fields::kKids);
785 if (!pKids) {
786 AddTerminalField(std::move(pFieldDict));
787 return;
788 }
789
790 RetainPtr<const CPDF_Dictionary> pFirstKid = pKids->GetDictAt(0);
791 if (!pFirstKid)
792 return;
793
794 if (!pFirstKid->KeyExist(pdfium::form_fields::kT) &&
795 !pFirstKid->KeyExist(pdfium::form_fields::kKids)) {
796 AddTerminalField(std::move(pFieldDict));
797 return;
798 }
799 for (size_t i = 0; i < pKids->size(); i++) {
800 RetainPtr<CPDF_Dictionary> pChildDict = pKids->GetMutableDictAt(i);
801 if (pChildDict && pChildDict->GetObjNum() != dwParentObjNum)
802 LoadField(std::move(pChildDict), nLevel + 1);
803 }
804}
805
806void CPDF_InteractiveForm::FixPageFields(CPDF_Page* pPage) {
807 RetainPtr<CPDF_Array> pAnnots = pPage->GetMutableAnnotsArray();
808 if (!pAnnots)
809 return;
810
811 for (size_t i = 0; i < pAnnots->size(); i++) {
812 RetainPtr<CPDF_Dictionary> pAnnot = pAnnots->GetMutableDictAt(i);
813 if (pAnnot && pAnnot->GetNameFor("Subtype") == "Widget")
814 LoadField(std::move(pAnnot), 0);
815 }
816}
817
818void CPDF_InteractiveForm::AddTerminalField(
819 RetainPtr<CPDF_Dictionary> pFieldDict) {
820 if (!pFieldDict->KeyExist(pdfium::form_fields::kFT)) {
821 // Key "FT" is required for terminal fields, it is also inheritable.
822 RetainPtr<const CPDF_Dictionary> pParentDict =
823 pFieldDict->GetDictFor(pdfium::form_fields::kParent);
824 if (!pParentDict || !pParentDict->KeyExist(pdfium::form_fields::kFT))
825 return;
826 }
827
828 WideString csWName = CPDF_FormField::GetFullNameForDict(pFieldDict.Get());
829 if (csWName.IsEmpty())
830 return;
831
832 CPDF_FormField* pField = nullptr;
833 pField = m_pFieldTree->GetField(csWName);
834 if (!pField) {
835 RetainPtr<CPDF_Dictionary> pParent(pFieldDict);
836 if (!pFieldDict->KeyExist(pdfium::form_fields::kT) &&
837 pFieldDict->GetNameFor("Subtype") == "Widget") {
838 pParent = pFieldDict->GetMutableDictFor(pdfium::form_fields::kParent);
839 if (!pParent)
840 pParent = pFieldDict;
841 }
842
843 if (pParent && pParent != pFieldDict &&
844 !pParent->KeyExist(pdfium::form_fields::kFT)) {
845 if (pFieldDict->KeyExist(pdfium::form_fields::kFT)) {
846 RetainPtr<const CPDF_Object> pFTValue =
847 pFieldDict->GetDirectObjectFor(pdfium::form_fields::kFT);
848 if (pFTValue)
849 pParent->SetFor(pdfium::form_fields::kFT, pFTValue->Clone());
850 }
851
852 if (pFieldDict->KeyExist(pdfium::form_fields::kFf)) {
853 RetainPtr<const CPDF_Object> pFfValue =
854 pFieldDict->GetDirectObjectFor(pdfium::form_fields::kFf);
855 if (pFfValue)
856 pParent->SetFor(pdfium::form_fields::kFf, pFfValue->Clone());
857 }
858 }
859
860 auto newField = std::make_unique<CPDF_FormField>(this, std::move(pParent));
861 pField = newField.get();
862 RetainPtr<const CPDF_Object> pTObj =
863 pFieldDict->GetObjectFor(pdfium::form_fields::kT);
864 if (ToReference(pTObj)) {
865 RetainPtr<CPDF_Object> pClone = pTObj->CloneDirectObject();
866 if (pClone)
867 pFieldDict->SetFor(pdfium::form_fields::kT, std::move(pClone));
868 else
869 pFieldDict->SetNewFor<CPDF_Name>(pdfium::form_fields::kT, ByteString());
870 }
871 if (!m_pFieldTree->SetField(csWName, std::move(newField)))
872 return;
873 }
874
875 RetainPtr<CPDF_Array> pKids =
876 pFieldDict->GetMutableArrayFor(pdfium::form_fields::kKids);
877 if (!pKids) {
878 if (pFieldDict->GetNameFor("Subtype") == "Widget")
879 AddControl(pField, std::move(pFieldDict));
880 return;
881 }
882 for (size_t i = 0; i < pKids->size(); i++) {
883 RetainPtr<CPDF_Dictionary> pKid = pKids->GetMutableDictAt(i);
884 if (pKid && pKid->GetNameFor("Subtype") == "Widget")
885 AddControl(pField, std::move(pKid));
886 }
887}
888
890 CPDF_FormField* pField,
891 RetainPtr<CPDF_Dictionary> pWidgetDict) {
892 DCHECK(pWidgetDict);
893 const auto it = m_ControlMap.find(pWidgetDict.Get());
894 if (it != m_ControlMap.end())
895 return it->second.get();
896
897 auto pNew = std::make_unique<CPDF_FormControl>(pField, pWidgetDict, this);
898 CPDF_FormControl* pControl = pNew.get();
899 m_ControlMap[pWidgetDict] = std::move(pNew);
900 m_ControlLists[pdfium::WrapUnowned(pField)].emplace_back(pControl);
901 return pControl;
902}
903
905 const std::vector<CPDF_FormField*>* fields,
906 bool bIncludeOrExclude) const {
907 CFieldTree::Node* pRoot = m_pFieldTree->GetRoot();
908 const size_t nCount = pRoot->CountFields();
909 for (size_t i = 0; i < nCount; ++i) {
910 CPDF_FormField* pField = pRoot->GetFieldAtIndex(i);
911 if (!pField)
912 continue;
913
914 int32_t iType = pField->GetType();
915 if (iType == CPDF_FormField::kPushButton ||
916 iType == CPDF_FormField::kCheckBox ||
917 iType == CPDF_FormField::kListBox) {
918 continue;
919 }
920 if (pField->IsNoExport())
921 continue;
922
923 bool bFind = true;
924 if (fields)
925 bFind = pdfium::Contains(*fields, pField);
926 if (bIncludeOrExclude == bFind) {
927 RetainPtr<const CPDF_Dictionary> pFieldDict = pField->GetFieldDict();
928 if (pField->IsRequired() &&
929 pFieldDict->GetByteStringFor(pdfium::form_fields::kV).IsEmpty()) {
930 return false;
931 }
932 }
933 }
934 return true;
935}
936
938 const WideString& pdf_path) const {
939 std::vector<CPDF_FormField*> fields;
940 CFieldTree::Node* pRoot = m_pFieldTree->GetRoot();
941 const size_t nCount = pRoot->CountFields();
942 for (size_t i = 0; i < nCount; ++i)
943 fields.push_back(pRoot->GetFieldAtIndex(i));
944 return ExportToFDF(pdf_path, fields, true);
945}
946
948 const WideString& pdf_path,
949 const std::vector<CPDF_FormField*>& fields,
950 bool bIncludeOrExclude) const {
951 std::unique_ptr<CFDF_Document> pDoc = CFDF_Document::CreateNewDoc();
952 if (!pDoc)
953 return nullptr;
954
955 RetainPtr<CPDF_Dictionary> pMainDict =
956 pDoc->GetMutableRoot()->GetMutableDictFor("FDF");
957 if (!pdf_path.IsEmpty()) {
958 auto pNewDict = pDoc->New<CPDF_Dictionary>();
959 pNewDict->SetNewFor<CPDF_Name>("Type", "Filespec");
961 pNewDict->SetNewFor<CPDF_String>(pdfium::stream::kF, wsStr.ToDefANSI());
962 pNewDict->SetNewFor<CPDF_String>("UF", wsStr.AsStringView());
963 pMainDict->SetFor("F", pNewDict);
964 }
965
966 auto pFields = pMainDict->SetNewFor<CPDF_Array>("Fields");
967 CFieldTree::Node* pRoot = m_pFieldTree->GetRoot();
968 const size_t nCount = pRoot->CountFields();
969 for (size_t i = 0; i < nCount; ++i) {
970 CPDF_FormField* pField = pRoot->GetFieldAtIndex(i);
971 if (!pField || pField->GetType() == CPDF_FormField::kPushButton)
972 continue;
973
974 uint32_t dwFlags = pField->GetFieldFlags();
975 if (dwFlags & pdfium::form_flags::kNoExport)
976 continue;
977
978 if (bIncludeOrExclude != pdfium::Contains(fields, pField))
979 continue;
980
981 if ((dwFlags & pdfium::form_flags::kRequired) != 0 &&
982 pField->GetFieldDict()
983 ->GetByteStringFor(pdfium::form_fields::kV)
984 .IsEmpty()) {
985 continue;
986 }
987
988 WideString fullname =
990 auto pFieldDict = pDoc->New<CPDF_Dictionary>();
991 pFieldDict->SetNewFor<CPDF_String>(pdfium::form_fields::kT,
992 fullname.AsStringView());
995 WideString csExport = pField->GetCheckValue(false);
996 ByteString csBExport = PDF_EncodeText(csExport.AsStringView());
997 RetainPtr<const CPDF_Object> pOpt = pField->GetFieldAttr("Opt");
998 if (pOpt) {
999 pFieldDict->SetNewFor<CPDF_String>(pdfium::form_fields::kV, csBExport);
1000 } else {
1001 pFieldDict->SetNewFor<CPDF_Name>(pdfium::form_fields::kV, csBExport);
1002 }
1003 } else {
1004 RetainPtr<const CPDF_Object> pV =
1005 pField->GetFieldAttr(pdfium::form_fields::kV);
1006 if (pV)
1007 pFieldDict->SetFor(pdfium::form_fields::kV, pV->CloneDirectObject());
1008 }
1009 pFields->Append(pFieldDict);
1010 }
1011 return pDoc;
1012}
1013
1015 m_pFormNotify = pNotify;
1016}
1017
1019 const WideString& csValue) {
1020 return !m_pFormNotify || m_pFormNotify->BeforeValueChange(pField, csValue);
1021}
1022
1024 if (m_pFormNotify)
1025 m_pFormNotify->AfterValueChange(pField);
1026}
1027
1029 CPDF_FormField* pField,
1030 const WideString& csValue) {
1031 return !m_pFormNotify ||
1032 m_pFormNotify->BeforeSelectionChange(pField, csValue);
1033}
1034
1036 if (m_pFormNotify)
1037 m_pFormNotify->AfterSelectionChange(pField);
1038}
1039
1041 CPDF_FormField* pField) {
1042 if (m_pFormNotify)
1043 m_pFormNotify->AfterCheckedStatusChange(pField);
1044}
fxcrt::ByteString ByteString
Definition bytestring.h:180
#define DCHECK
Definition check.h:33
bool Contains(const CFX_PointF &point) const
static const char kDefaultAnsiFontName[]
Definition cfx_font.h:54
void AddChildNode(std::unique_ptr< Node > pNode)
CPDF_FormField * GetFieldAtIndex(size_t index)
size_t GetChildrenCount() const
CPDF_FormField * GetField() const
Node(const WideString &short_name, int level)
const Node * GetChildAt(size_t i) const
void SetField(std::unique_ptr< CPDF_FormField > pField)
WideString GetShortName() const
Node * GetChildAt(size_t i)
bool SetField(const WideString &full_name, std::unique_ptr< CPDF_FormField > pField)
CPDF_FormField * GetField(const WideString &full_name)
Node * AddChild(Node *pParent, const WideString &short_name)
Node * Lookup(Node *pParent, WideStringView short_name)
Node * FindNode(const WideString &full_name)
std::vector< RetainPtr< CPDF_Object > >::const_iterator const_iterator
Definition cpdf_array.h:29
std::map< ByteString, RetainPtr< CPDF_Object >, std::less<> > DictMap
static CPDF_DocPageData * FromDocument(const CPDF_Document *pDoc)
RetainPtr< CPDF_Font > AddStandardFont(const ByteString &fontName, const CPDF_FontEncoding *pEncoding)
static WideString EncodeFileName(const WideString &filepath)
CPDF_FontEncoding(FontEncoding predefined_encoding)
CFX_FloatRect GetRect() const
static WideString GetFullNameForDict(const CPDF_Dictionary *pFieldDict)
uint32_t GetFieldFlags() const
bool IsRequired() const
bool IsNoExport() const
WideString GetCheckValue(bool bDefault) const
Type GetType() const
RetainPtr< const CPDF_Dictionary > GetFieldDict() const
RetainPtr< CPDF_Font > GetFontForElement(RetainPtr< CPDF_Dictionary > pElement) const
CPDF_FormField * GetFieldInCalculationOrder(int index)
bool NotifyBeforeSelectionChange(CPDF_FormField *pField, const WideString &csValue)
bool NotifyBeforeValueChange(CPDF_FormField *pField, const WideString &csValue)
void SetNotifierIface(NotifierIface *pNotify)
static void SetUpdateAP(bool bUpdateAP)
bool CheckRequiredFields(const std::vector< CPDF_FormField * > *fields, bool bIncludeOrExclude) const
size_t CountFields(const WideString &csFieldName) const
std::unique_ptr< CFDF_Document > ExportToFDF(const WideString &pdf_path) const
const CPDF_FormControl * GetControlAtPoint(const CPDF_Page *pPage, const CFX_PointF &point, int *z_order) const
std::unique_ptr< CFDF_Document > ExportToFDF(const WideString &pdf_path, const std::vector< CPDF_FormField * > &fields, bool bIncludeOrExclude) const
void NotifyAfterSelectionChange(CPDF_FormField *pField)
CPDF_InteractiveForm(CPDF_Document *pDocument)
void NotifyAfterValueChange(CPDF_FormField *pField)
int FindFieldInCalculationOrder(const CPDF_FormField *pField)
CPDF_FormControl * GetControlByDict(const CPDF_Dictionary *pWidgetDict) const
void FixPageFields(CPDF_Page *pPage)
static RetainPtr< CPDF_Font > AddNativeInteractiveFormFont(CPDF_Document *pDocument, ByteString *csNameTag)
CPDF_FormField * GetField(size_t index, const WideString &csFieldName) const
const std::vector< UnownedPtr< CPDF_FormControl > > & GetControlsForField(const CPDF_FormField *pField)
CPDF_DefaultAppearance GetDefaultAppearance() const
CPDF_FormField * GetFieldByDict(const CPDF_Dictionary *pFieldDict) const
void ResetForm(pdfium::span< CPDF_FormField * > fields, bool bIncludeOrExclude)
RetainPtr< CPDF_Font > GetFormFont(ByteString csNameTag) const
void NotifyAfterCheckedStatusChange(CPDF_FormField *pField)
ByteString()=default
static ByteString FormatInteger(int i)
ByteString & operator+=(const char *str)
ByteString & operator=(const char *str)
ByteString & operator=(ByteString &&that) noexcept
bool operator!=(const char *ptr) const
Definition bytestring.h:65
ByteString ToDefANSI() const
FontEncoding
ByteString PDF_NameEncode(const ByteString &orig)
FX_Charset
Definition fx_codepage.h:71
FX_Charset FX_GetCharsetFromCodePage(FX_CodePage codepage)
FX_CodePage FX_GetACP()
CFX_PTemplate< float > CFX_PointF
ByteString operator+(const ByteString &str1, const ByteString &str2)
Definition bytestring.h:146
ByteString operator+(const ByteString &str1, const char *str2)
Definition bytestring.h:155
ByteString operator+(const char *str1, const ByteString &str2)
Definition bytestring.h:158
const char kParent[]
constexpr uint32_t kNoExport
Definition form_flags.h:15
fxcrt::WideStringView WideStringView
fxcrt::WideString WideString
Definition widestring.h:207