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
39 namespace {
40
41 const int nMaxRecursion = 32;
42
43 #if BUILDFLAG(IS_WIN)
44 struct PDF_FONTDATA {
45 bool bFind;
46 LOGFONTA lf;
47 };
48
EnumFontFamExProc(ENUMLOGFONTEXA * lpelfe,NEWTEXTMETRICEX * lpntme,DWORD FontType,LPARAM lParam)49 int 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
RetrieveSpecificFont(FX_Charset charSet,LPCSTR pcsFontName,LOGFONTA & lf)62 bool 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
GetNativeFontName(FX_Charset charSet,void * pLogFont)87 ByteString 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
GenerateNewFontResourceName(const CPDF_Dictionary * pResDict,const ByteString & csPrefix)117 ByteString 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
AddStandardFont(CPDF_Document * pDocument)152 RetainPtr<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
AddNativeFont(FX_Charset charSet,CPDF_Document * pDocument)158 RetainPtr<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
FindFont(const CPDF_Dictionary * pFormDict,const CPDF_Font * pFont,ByteString * csNameTag)174 bool 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
FindFontFromDoc(const CPDF_Dictionary * pFormDict,CPDF_Document * pDocument,ByteString csFontName,RetainPtr<CPDF_Font> & pFont,ByteString * csNameTag)201 bool 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
AddFont(CPDF_Dictionary * pFormDict,CPDF_Document * pDocument,const RetainPtr<CPDF_Font> & pFont,ByteString * csNameTag)241 void 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
GetNativeCharSet()266 FX_Charset GetNativeCharSet() {
267 return FX_GetCharsetFromCodePage(FX_GetACP());
268 }
269
InitDict(CPDF_Document * pDocument)270 RetainPtr<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
GetNativeFont(const CPDF_Dictionary * pFormDict,CPDF_Document * pDocument,FX_Charset charSet,ByteString * csNameTag)299 RetainPtr<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
333 class CFieldNameExtractor {
334 public:
CFieldNameExtractor(const WideString & full_name)335 explicit CFieldNameExtractor(const WideString& full_name)
336 : m_FullName(full_name) {}
337
GetNext()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
357 class CFieldTree {
358 public:
359 class Node {
360 public:
Node()361 Node() : m_level(0) {}
Node(const WideString & short_name,int level)362 Node(const WideString& short_name, int level)
363 : m_ShortName(short_name), m_level(level) {}
364 ~Node() = default;
365
AddChildNode(std::unique_ptr<Node> pNode)366 void AddChildNode(std::unique_ptr<Node> pNode) {
367 m_Children.push_back(std::move(pNode));
368 }
369
GetChildrenCount() const370 size_t GetChildrenCount() const { return m_Children.size(); }
371
GetChildAt(size_t i)372 Node* GetChildAt(size_t i) { return m_Children[i].get(); }
GetChildAt(size_t i) const373 const Node* GetChildAt(size_t i) const { return m_Children[i].get(); }
374
GetFieldAtIndex(size_t index)375 CPDF_FormField* GetFieldAtIndex(size_t index) {
376 size_t nFieldsToGo = index;
377 return GetFieldInternal(&nFieldsToGo);
378 }
379
CountFields() const380 size_t CountFields() const { return CountFieldsInternal(); }
381
SetField(std::unique_ptr<CPDF_FormField> pField)382 void SetField(std::unique_ptr<CPDF_FormField> pField) {
383 m_pField = std::move(pField);
384 }
385
GetField() const386 CPDF_FormField* GetField() const { return m_pField.get(); }
GetShortName() const387 WideString GetShortName() const { return m_ShortName; }
GetLevel() const388 int GetLevel() const { return m_level; }
389
390 private:
GetFieldInternal(size_t * pFieldsToGo)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
CountFieldsInternal() const406 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
422 CFieldTree();
423 ~CFieldTree();
424
425 bool SetField(const WideString& full_name,
426 std::unique_ptr<CPDF_FormField> pField);
427 CPDF_FormField* GetField(const WideString& full_name);
428
GetRoot()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
CFieldTree()438 CFieldTree::CFieldTree() : m_pRoot(std::make_unique<Node>()) {}
439
440 CFieldTree::~CFieldTree() = default;
441
AddChild(Node * pParent,const WideString & short_name)442 CFieldTree::Node* CFieldTree::AddChild(Node* pParent,
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
Lookup(Node * pParent,WideStringView short_name)457 CFieldTree::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
SetField(const WideString & full_name,std::unique_ptr<CPDF_FormField> pField)469 bool 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
GetField(const WideString & full_name)496 CPDF_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
FindNode(const WideString & full_name)513 CFieldTree::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
CPDF_InteractiveForm(CPDF_Document * pDocument)530 CPDF_InteractiveForm::CPDF_InteractiveForm(CPDF_Document* pDocument)
531 : m_pDocument(pDocument), m_pFieldTree(std::make_unique<CFieldTree>()) {
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
548 CPDF_InteractiveForm::~CPDF_InteractiveForm() = default;
549
550 bool CPDF_InteractiveForm::s_bUpdateAP = true;
551
552 // static
IsUpdateAPEnabled()553 bool CPDF_InteractiveForm::IsUpdateAPEnabled() {
554 return s_bUpdateAP;
555 }
556
557 // static
SetUpdateAP(bool bUpdateAP)558 void CPDF_InteractiveForm::SetUpdateAP(bool bUpdateAP) {
559 s_bUpdateAP = bUpdateAP;
560 }
561
562 // static
AddNativeInteractiveFormFont(CPDF_Document * pDocument,ByteString * csNameTag)563 RetainPtr<CPDF_Font> CPDF_InteractiveForm::AddNativeInteractiveFormFont(
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
CountFields(const WideString & csFieldName) const594 size_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
GetField(size_t index,const WideString & csFieldName) const602 CPDF_FormField* CPDF_InteractiveForm::GetField(
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
GetFieldByDict(const CPDF_Dictionary * pFieldDict) const612 CPDF_FormField* CPDF_InteractiveForm::GetFieldByDict(
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
GetControlAtPoint(const CPDF_Page * pPage,const CFX_PointF & point,int * z_order) const621 const CPDF_FormControl* CPDF_InteractiveForm::GetControlAtPoint(
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
GetControlByDict(const CPDF_Dictionary * pWidgetDict) const651 CPDF_FormControl* CPDF_InteractiveForm::GetControlByDict(
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
NeedConstructAP() const657 bool CPDF_InteractiveForm::NeedConstructAP() const {
658 return m_pFormDict && m_pFormDict->GetBooleanFor("NeedAppearances", false);
659 }
660
CountFieldsInCalculationOrder()661 int CPDF_InteractiveForm::CountFieldsInCalculationOrder() {
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
GetFieldInCalculationOrder(int index)669 CPDF_FormField* CPDF_InteractiveForm::GetFieldInCalculationOrder(int index) {
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
FindFieldInCalculationOrder(const CPDF_FormField * pField)682 int CPDF_InteractiveForm::FindFieldInCalculationOrder(
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
GetFormFont(ByteString csNameTag) const698 RetainPtr<CPDF_Font> CPDF_InteractiveForm::GetFormFont(
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
GetFontForElement(RetainPtr<CPDF_Dictionary> pElement) const719 RetainPtr<CPDF_Font> CPDF_InteractiveForm::GetFontForElement(
720 RetainPtr<CPDF_Dictionary> pElement) const {
721 auto* pData = CPDF_DocPageData::FromDocument(m_pDocument);
722 return pData->GetFont(std::move(pElement));
723 }
724
GetDefaultAppearance() const725 CPDF_DefaultAppearance CPDF_InteractiveForm::GetDefaultAppearance() const {
726 if (!m_pFormDict)
727 return CPDF_DefaultAppearance();
728 return CPDF_DefaultAppearance(m_pFormDict->GetByteStringFor("DA"));
729 }
730
GetFormAlignment() const731 int CPDF_InteractiveForm::GetFormAlignment() const {
732 return m_pFormDict ? m_pFormDict->GetIntegerFor("Q", 0) : 0;
733 }
734
ResetForm(pdfium::span<CPDF_FormField * > fields,bool bIncludeOrExclude)735 void CPDF_InteractiveForm::ResetForm(pdfium::span<CPDF_FormField*> fields,
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
ResetForm()751 void CPDF_InteractiveForm::ResetForm() {
752 ResetForm(/*fields=*/{}, /*bIncludeOrExclude=*/false);
753 }
754
755 const std::vector<UnownedPtr<CPDF_FormControl>>&
GetControlsForField(const CPDF_FormField * pField)756 CPDF_InteractiveForm::GetControlsForField(const CPDF_FormField* pField) {
757 return m_ControlLists[pdfium::WrapUnowned(pField)];
758 }
759
LoadField(RetainPtr<CPDF_Dictionary> pFieldDict,int nLevel)760 void 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
FixPageFields(CPDF_Page * pPage)791 void 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
AddTerminalField(RetainPtr<CPDF_Dictionary> pFieldDict)803 void 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
AddControl(CPDF_FormField * pField,RetainPtr<CPDF_Dictionary> pWidgetDict)874 CPDF_FormControl* CPDF_InteractiveForm::AddControl(
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
CheckRequiredFields(const std::vector<CPDF_FormField * > * fields,bool bIncludeOrExclude) const889 bool CPDF_InteractiveForm::CheckRequiredFields(
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
ExportToFDF(const WideString & pdf_path) const922 std::unique_ptr<CFDF_Document> CPDF_InteractiveForm::ExportToFDF(
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
ExportToFDF(const WideString & pdf_path,const std::vector<CPDF_FormField * > & fields,bool bIncludeOrExclude) const932 std::unique_ptr<CFDF_Document> CPDF_InteractiveForm::ExportToFDF(
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 =
975 CPDF_FormField::GetFullNameForDict(pField->GetFieldDict());
976 auto pFieldDict = pDoc->New<CPDF_Dictionary>();
977 pFieldDict->SetNewFor<CPDF_String>(pdfium::form_fields::kT,
978 fullname.AsStringView());
979 if (pField->GetType() == CPDF_FormField::kCheckBox ||
980 pField->GetType() == CPDF_FormField::kRadioButton) {
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
SetNotifierIface(NotifierIface * pNotify)1001 void CPDF_InteractiveForm::SetNotifierIface(NotifierIface* pNotify) {
1002 m_pFormNotify = pNotify;
1003 }
1004
NotifyBeforeValueChange(CPDF_FormField * pField,const WideString & csValue)1005 bool CPDF_InteractiveForm::NotifyBeforeValueChange(CPDF_FormField* pField,
1006 const WideString& csValue) {
1007 return !m_pFormNotify || m_pFormNotify->BeforeValueChange(pField, csValue);
1008 }
1009
NotifyAfterValueChange(CPDF_FormField * pField)1010 void CPDF_InteractiveForm::NotifyAfterValueChange(CPDF_FormField* pField) {
1011 if (m_pFormNotify)
1012 m_pFormNotify->AfterValueChange(pField);
1013 }
1014
NotifyBeforeSelectionChange(CPDF_FormField * pField,const WideString & csValue)1015 bool CPDF_InteractiveForm::NotifyBeforeSelectionChange(
1016 CPDF_FormField* pField,
1017 const WideString& csValue) {
1018 return !m_pFormNotify ||
1019 m_pFormNotify->BeforeSelectionChange(pField, csValue);
1020 }
1021
NotifyAfterSelectionChange(CPDF_FormField * pField)1022 void CPDF_InteractiveForm::NotifyAfterSelectionChange(CPDF_FormField* pField) {
1023 if (m_pFormNotify)
1024 m_pFormNotify->AfterSelectionChange(pField);
1025 }
1026
NotifyAfterCheckedStatusChange(CPDF_FormField * pField)1027 void CPDF_InteractiveForm::NotifyAfterCheckedStatusChange(
1028 CPDF_FormField* pField) {
1029 if (m_pFormNotify)
1030 m_pFormNotify->AfterCheckedStatusChange(pField);
1031 }
1032