• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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