• 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 <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