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