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
46 namespace {
47
48 const int nMaxRecursion = 32;
49
50 #if BUILDFLAG(IS_WIN)
51 struct PDF_FONTDATA {
52 bool bFind;
53 LOGFONTA lf;
54 };
55
EnumFontFamExProc(ENUMLOGFONTEXA * lpelfe,NEWTEXTMETRICEX * lpntme,DWORD FontType,LPARAM lParam)56 int 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
RetrieveSpecificFont(FX_Charset charSet,LPCSTR pcsFontName,LOGFONTA & lf)69 bool 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
GetNativeFontName(FX_Charset charSet,void * pLogFont)95 ByteString 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
GenerateNewFontResourceName(const CPDF_Dictionary * pResDict,const ByteString & csPrefix)133 ByteString 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
163 bsNum = ByteString::FormatInteger(num++);
164 m++;
165 }
166 }
167
AddStandardFont(CPDF_Document * pDocument)168 RetainPtr<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
AddNativeFont(FX_Charset charSet,CPDF_Document * pDocument)174 RetainPtr<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
FindFont(const CPDF_Dictionary * pFormDict,const CPDF_Font * pFont,ByteString * csNameTag)190 bool 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
FindFontFromDoc(const CPDF_Dictionary * pFormDict,CPDF_Document * pDocument,ByteString csFontName,RetainPtr<CPDF_Font> & pFont,ByteString * csNameTag)217 bool 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
AddFont(CPDF_Dictionary * pFormDict,CPDF_Document * pDocument,const RetainPtr<CPDF_Font> & pFont,ByteString * csNameTag)257 void 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
GetNativeCharSet()282 FX_Charset GetNativeCharSet() {
283 return FX_GetCharsetFromCodePage(FX_GetACP());
284 }
285
InitDict(CPDF_Document * pDocument)286 RetainPtr<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
GetNativeFont(const CPDF_Dictionary * pFormDict,CPDF_Document * pDocument,FX_Charset charSet,ByteString * csNameTag)315 RetainPtr<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
349 class CFieldNameExtractor {
350 public:
CFieldNameExtractor(const WideString & full_name)351 explicit CFieldNameExtractor(const WideString& full_name)
352 : m_FullName(full_name) {}
353
GetNext()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
373 class CFieldTree {
374 public:
375 class Node {
376 public:
Node()377 Node() : m_level(0) {}
Node(const WideString & short_name,int level)378 Node(const WideString& short_name, int level)
379 : m_ShortName(short_name), m_level(level) {}
380 ~Node() = default;
381
AddChildNode(std::unique_ptr<Node> pNode)382 void AddChildNode(std::unique_ptr<Node> pNode) {
383 m_Children.push_back(std::move(pNode));
384 }
385
GetChildrenCount() const386 size_t GetChildrenCount() const { return m_Children.size(); }
387
GetChildAt(size_t i)388 Node* GetChildAt(size_t i) { return m_Children[i].get(); }
GetChildAt(size_t i) const389 const Node* GetChildAt(size_t i) const { return m_Children[i].get(); }
390
GetFieldAtIndex(size_t index)391 CPDF_FormField* GetFieldAtIndex(size_t index) {
392 size_t nFieldsToGo = index;
393 return GetFieldInternal(&nFieldsToGo);
394 }
395
CountFields() const396 size_t CountFields() const { return CountFieldsInternal(); }
397
SetField(std::unique_ptr<CPDF_FormField> pField)398 void SetField(std::unique_ptr<CPDF_FormField> pField) {
399 m_pField = std::move(pField);
400 }
401
GetField() const402 CPDF_FormField* GetField() const { return m_pField.get(); }
GetShortName() const403 WideString GetShortName() const { return m_ShortName; }
GetLevel() const404 int GetLevel() const { return m_level; }
405
406 private:
GetFieldInternal(size_t * pFieldsToGo)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
CountFieldsInternal() const422 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
438 CFieldTree();
439 ~CFieldTree();
440
441 bool SetField(const WideString& full_name,
442 std::unique_ptr<CPDF_FormField> pField);
443 CPDF_FormField* GetField(const WideString& full_name);
444
GetRoot()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
CFieldTree()454 CFieldTree::CFieldTree() : m_pRoot(std::make_unique<Node>()) {}
455
456 CFieldTree::~CFieldTree() = default;
457
AddChild(Node * pParent,const WideString & short_name)458 CFieldTree::Node* CFieldTree::AddChild(Node* pParent,
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
Lookup(Node * pParent,WideStringView short_name)473 CFieldTree::Node* CFieldTree::Lookup(Node* pParent, WideStringView short_name) {
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
SetField(const WideString & full_name,std::unique_ptr<CPDF_FormField> pField)485 bool 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
GetField(const WideString & full_name)512 CPDF_FormField* CFieldTree::GetField(const WideString& full_name) {
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
FindNode(const WideString & full_name)529 CFieldTree::Node* CFieldTree::FindNode(const WideString& full_name) {
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
CPDF_InteractiveForm(CPDF_Document * pDocument)546 CPDF_InteractiveForm::CPDF_InteractiveForm(CPDF_Document* pDocument)
547 : m_pDocument(pDocument), m_pFieldTree(std::make_unique<CFieldTree>()) {
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
564 CPDF_InteractiveForm::~CPDF_InteractiveForm() = default;
565
566 bool CPDF_InteractiveForm::s_bUpdateAP = true;
567
568 // static
IsUpdateAPEnabled()569 bool CPDF_InteractiveForm::IsUpdateAPEnabled() {
570 return s_bUpdateAP;
571 }
572
573 // static
SetUpdateAP(bool bUpdateAP)574 void CPDF_InteractiveForm::SetUpdateAP(bool bUpdateAP) {
575 s_bUpdateAP = bUpdateAP;
576 }
577
578 // static
AddNativeInteractiveFormFont(CPDF_Document * pDocument,ByteString * csNameTag)579 RetainPtr<CPDF_Font> CPDF_InteractiveForm::AddNativeInteractiveFormFont(
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
CountFields(const WideString & csFieldName) const610 size_t CPDF_InteractiveForm::CountFields(const WideString& csFieldName) const {
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
GetField(size_t index,const WideString & csFieldName) const618 CPDF_FormField* CPDF_InteractiveForm::GetField(
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
GetFieldByDict(const CPDF_Dictionary * pFieldDict) const628 CPDF_FormField* CPDF_InteractiveForm::GetFieldByDict(
629 const CPDF_Dictionary* pFieldDict) const {
630 if (!pFieldDict)
631 return nullptr;
632
633 WideString csWName = CPDF_FormField::GetFullNameForDict(pFieldDict);
634 return m_pFieldTree->GetField(csWName);
635 }
636
GetControlAtPoint(const CPDF_Page * pPage,const CFX_PointF & point,int * z_order) const637 const CPDF_FormControl* CPDF_InteractiveForm::GetControlAtPoint(
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
GetControlByDict(const CPDF_Dictionary * pWidgetDict) const667 CPDF_FormControl* CPDF_InteractiveForm::GetControlByDict(
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
NeedConstructAP() const673 bool CPDF_InteractiveForm::NeedConstructAP() const {
674 return m_pFormDict && m_pFormDict->GetBooleanFor("NeedAppearances", false);
675 }
676
CountFieldsInCalculationOrder()677 int CPDF_InteractiveForm::CountFieldsInCalculationOrder() {
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
GetFieldInCalculationOrder(int index)685 CPDF_FormField* CPDF_InteractiveForm::GetFieldInCalculationOrder(int index) {
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
FindFieldInCalculationOrder(const CPDF_FormField * pField)698 int CPDF_InteractiveForm::FindFieldInCalculationOrder(
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
GetFormFont(ByteString csNameTag) const714 RetainPtr<CPDF_Font> CPDF_InteractiveForm::GetFormFont(
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
GetFontForElement(RetainPtr<CPDF_Dictionary> pElement) const735 RetainPtr<CPDF_Font> CPDF_InteractiveForm::GetFontForElement(
736 RetainPtr<CPDF_Dictionary> pElement) const {
737 auto* pData = CPDF_DocPageData::FromDocument(m_pDocument);
738 return pData->GetFont(std::move(pElement));
739 }
740
GetDefaultAppearance() const741 CPDF_DefaultAppearance CPDF_InteractiveForm::GetDefaultAppearance() const {
742 return CPDF_DefaultAppearance(
743 m_pFormDict ? m_pFormDict->GetByteStringFor("DA") : "");
744 }
745
GetFormAlignment() const746 int CPDF_InteractiveForm::GetFormAlignment() const {
747 return m_pFormDict ? m_pFormDict->GetIntegerFor("Q", 0) : 0;
748 }
749
ResetForm(pdfium::span<CPDF_FormField * > fields,bool bIncludeOrExclude)750 void 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
ResetForm()766 void CPDF_InteractiveForm::ResetForm() {
767 ResetForm(/*fields=*/{}, /*bIncludeOrExclude=*/false);
768 }
769
770 const std::vector<UnownedPtr<CPDF_FormControl>>&
GetControlsForField(const CPDF_FormField * pField)771 CPDF_InteractiveForm::GetControlsForField(const CPDF_FormField* pField) {
772 return m_ControlLists[pdfium::WrapUnowned(pField)];
773 }
774
LoadField(RetainPtr<CPDF_Dictionary> pFieldDict,int nLevel)775 void 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
FixPageFields(CPDF_Page * pPage)806 void 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
AddTerminalField(RetainPtr<CPDF_Dictionary> pFieldDict)818 void 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
AddControl(CPDF_FormField * pField,RetainPtr<CPDF_Dictionary> pWidgetDict)889 CPDF_FormControl* CPDF_InteractiveForm::AddControl(
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
CheckRequiredFields(const std::vector<CPDF_FormField * > * fields,bool bIncludeOrExclude) const904 bool CPDF_InteractiveForm::CheckRequiredFields(
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
ExportToFDF(const WideString & pdf_path) const937 std::unique_ptr<CFDF_Document> CPDF_InteractiveForm::ExportToFDF(
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
ExportToFDF(const WideString & pdf_path,const std::vector<CPDF_FormField * > & fields,bool bIncludeOrExclude) const947 std::unique_ptr<CFDF_Document> CPDF_InteractiveForm::ExportToFDF(
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");
960 WideString wsStr = CPDF_FileSpec::EncodeFileName(pdf_path);
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 =
989 CPDF_FormField::GetFullNameForDict(pField->GetFieldDict());
990 auto pFieldDict = pDoc->New<CPDF_Dictionary>();
991 pFieldDict->SetNewFor<CPDF_String>(pdfium::form_fields::kT,
992 fullname.AsStringView());
993 if (pField->GetType() == CPDF_FormField::kCheckBox ||
994 pField->GetType() == CPDF_FormField::kRadioButton) {
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
SetNotifierIface(NotifierIface * pNotify)1014 void CPDF_InteractiveForm::SetNotifierIface(NotifierIface* pNotify) {
1015 m_pFormNotify = pNotify;
1016 }
1017
NotifyBeforeValueChange(CPDF_FormField * pField,const WideString & csValue)1018 bool CPDF_InteractiveForm::NotifyBeforeValueChange(CPDF_FormField* pField,
1019 const WideString& csValue) {
1020 return !m_pFormNotify || m_pFormNotify->BeforeValueChange(pField, csValue);
1021 }
1022
NotifyAfterValueChange(CPDF_FormField * pField)1023 void CPDF_InteractiveForm::NotifyAfterValueChange(CPDF_FormField* pField) {
1024 if (m_pFormNotify)
1025 m_pFormNotify->AfterValueChange(pField);
1026 }
1027
NotifyBeforeSelectionChange(CPDF_FormField * pField,const WideString & csValue)1028 bool CPDF_InteractiveForm::NotifyBeforeSelectionChange(
1029 CPDF_FormField* pField,
1030 const WideString& csValue) {
1031 return !m_pFormNotify ||
1032 m_pFormNotify->BeforeSelectionChange(pField, csValue);
1033 }
1034
NotifyAfterSelectionChange(CPDF_FormField * pField)1035 void CPDF_InteractiveForm::NotifyAfterSelectionChange(CPDF_FormField* pField) {
1036 if (m_pFormNotify)
1037 m_pFormNotify->AfterSelectionChange(pField);
1038 }
1039
NotifyAfterCheckedStatusChange(CPDF_FormField * pField)1040 void CPDF_InteractiveForm::NotifyAfterCheckedStatusChange(
1041 CPDF_FormField* pField) {
1042 if (m_pFormNotify)
1043 m_pFormNotify->AfterCheckedStatusChange(pField);
1044 }
1045