1// Copyright 2014 PDFium Authors. All rights reserved.
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/include/fpdfdoc/fpdf_doc.h"
8#include "doc_utils.h"
9#include "third_party/base/stl_util.h"
10
11const int nMaxRecursion = 32;
12
13class CFieldNameExtractor {
14 public:
15  explicit CFieldNameExtractor(const CFX_WideString& full_name) {
16    m_pStart = full_name.c_str();
17    m_pEnd = m_pStart + full_name.GetLength();
18    m_pCur = m_pStart;
19  }
20  void GetNext(const FX_WCHAR*& pSubName, FX_STRSIZE& size) {
21    pSubName = m_pCur;
22    while (m_pCur < m_pEnd && m_pCur[0] != L'.') {
23      m_pCur++;
24    }
25    size = (FX_STRSIZE)(m_pCur - pSubName);
26    if (m_pCur < m_pEnd && m_pCur[0] == L'.') {
27      m_pCur++;
28    }
29  }
30
31 protected:
32  const FX_WCHAR* m_pStart;
33  const FX_WCHAR* m_pEnd;
34  const FX_WCHAR* m_pCur;
35};
36class CFieldTree {
37 public:
38  struct _Node {
39    _Node* parent;
40    CFX_ArrayTemplate<_Node*> children;
41    CFX_WideString short_name;
42    CPDF_FormField* field_ptr;
43    int CountFields(int nLevel = 0) {
44      if (nLevel > nMaxRecursion) {
45        return 0;
46      }
47      if (field_ptr) {
48        return 1;
49      }
50      int count = 0;
51      for (int i = 0; i < children.GetSize(); i++) {
52        count += children.GetAt(i)->CountFields(nLevel + 1);
53      }
54      return count;
55    }
56    CPDF_FormField* GetField(int* fields_to_go) {
57      if (field_ptr) {
58        if (*fields_to_go == 0) {
59          return field_ptr;
60        }
61        --*fields_to_go;
62        return NULL;
63      }
64      for (int i = 0; i < children.GetSize(); i++) {
65        if (CPDF_FormField* pField = children.GetAt(i)->GetField(fields_to_go))
66          return pField;
67      }
68      return NULL;
69    }
70    CPDF_FormField* GetField(int index) {
71      int fields_to_go = index;
72      return GetField(&fields_to_go);
73    }
74  };
75  CFieldTree();
76  ~CFieldTree();
77  void SetField(const CFX_WideString& full_name, CPDF_FormField* field_ptr);
78  CPDF_FormField* GetField(const CFX_WideString& full_name);
79  CPDF_FormField* RemoveField(const CFX_WideString& full_name);
80  void RemoveAll();
81  _Node* FindNode(const CFX_WideString& full_name);
82  _Node* AddChild(_Node* pParent,
83                  const CFX_WideString& short_name,
84                  CPDF_FormField* field_ptr);
85  void RemoveNode(_Node* pNode, int nLevel = 0);
86  _Node* _Lookup(_Node* pParent, const CFX_WideString& short_name);
87  _Node m_Root;
88};
89CFieldTree::CFieldTree() {
90  m_Root.parent = NULL;
91  m_Root.field_ptr = NULL;
92}
93CFieldTree::~CFieldTree() {
94  RemoveAll();
95}
96CFieldTree::_Node* CFieldTree::AddChild(_Node* pParent,
97                                        const CFX_WideString& short_name,
98                                        CPDF_FormField* field_ptr) {
99  if (!pParent) {
100    return NULL;
101  }
102  _Node* pNode = new _Node;
103  pNode->parent = pParent;
104  pNode->short_name = short_name;
105  pNode->field_ptr = field_ptr;
106  pParent->children.Add(pNode);
107  return pNode;
108}
109void CFieldTree::RemoveNode(_Node* pNode, int nLevel) {
110  if (!pNode) {
111    return;
112  }
113  if (nLevel <= nMaxRecursion) {
114    for (int i = 0; i < pNode->children.GetSize(); i++) {
115      RemoveNode(pNode->children[i], nLevel + 1);
116    }
117  }
118  delete pNode;
119}
120CFieldTree::_Node* CFieldTree::_Lookup(_Node* pParent,
121                                       const CFX_WideString& short_name) {
122  if (!pParent) {
123    return NULL;
124  }
125  for (int i = 0; i < pParent->children.GetSize(); i++) {
126    _Node* pNode = pParent->children[i];
127    if (pNode->short_name.GetLength() == short_name.GetLength() &&
128        FXSYS_memcmp(pNode->short_name.c_str(), short_name.c_str(),
129                     short_name.GetLength() * sizeof(FX_WCHAR)) == 0) {
130      return pNode;
131    }
132  }
133  return NULL;
134}
135void CFieldTree::RemoveAll() {
136  for (int i = 0; i < m_Root.children.GetSize(); i++) {
137    RemoveNode(m_Root.children[i]);
138  }
139}
140void CFieldTree::SetField(const CFX_WideString& full_name,
141                          CPDF_FormField* field_ptr) {
142  if (full_name == L"") {
143    return;
144  }
145  CFieldNameExtractor name_extractor(full_name);
146  const FX_WCHAR* pName;
147  FX_STRSIZE nLength;
148  name_extractor.GetNext(pName, nLength);
149  _Node *pNode = &m_Root, *pLast = NULL;
150  while (nLength > 0) {
151    pLast = pNode;
152    CFX_WideString name = CFX_WideString(pName, nLength);
153    pNode = _Lookup(pLast, name);
154    if (!pNode) {
155      pNode = AddChild(pLast, name, NULL);
156    }
157    name_extractor.GetNext(pName, nLength);
158  }
159  if (pNode != &m_Root) {
160    pNode->field_ptr = field_ptr;
161  }
162}
163CPDF_FormField* CFieldTree::GetField(const CFX_WideString& full_name) {
164  if (full_name == L"") {
165    return NULL;
166  }
167  CFieldNameExtractor name_extractor(full_name);
168  const FX_WCHAR* pName;
169  FX_STRSIZE nLength;
170  name_extractor.GetNext(pName, nLength);
171  _Node *pNode = &m_Root, *pLast = NULL;
172  while (nLength > 0 && pNode) {
173    pLast = pNode;
174    CFX_WideString name = CFX_WideString(pName, nLength);
175    pNode = _Lookup(pLast, name);
176    name_extractor.GetNext(pName, nLength);
177  }
178  return pNode ? pNode->field_ptr : NULL;
179}
180CPDF_FormField* CFieldTree::RemoveField(const CFX_WideString& full_name) {
181  if (full_name == L"") {
182    return NULL;
183  }
184  CFieldNameExtractor name_extractor(full_name);
185  const FX_WCHAR* pName;
186  FX_STRSIZE nLength;
187  name_extractor.GetNext(pName, nLength);
188  _Node *pNode = &m_Root, *pLast = NULL;
189  while (nLength > 0 && pNode) {
190    pLast = pNode;
191    CFX_WideString name = CFX_WideString(pName, nLength);
192    pNode = _Lookup(pLast, name);
193    name_extractor.GetNext(pName, nLength);
194  }
195  if (pNode && pNode != &m_Root) {
196    for (int i = 0; i < pLast->children.GetSize(); i++) {
197      if (pNode == pLast->children[i]) {
198        pLast->children.RemoveAt(i);
199        break;
200      }
201    }
202    CPDF_FormField* pField = pNode->field_ptr;
203    RemoveNode(pNode);
204    return pField;
205  }
206  return NULL;
207}
208CFieldTree::_Node* CFieldTree::FindNode(const CFX_WideString& full_name) {
209  if (full_name == L"") {
210    return NULL;
211  }
212  CFieldNameExtractor name_extractor(full_name);
213  const FX_WCHAR* pName;
214  FX_STRSIZE nLength;
215  name_extractor.GetNext(pName, nLength);
216  _Node *pNode = &m_Root, *pLast = NULL;
217  while (nLength > 0 && pNode) {
218    pLast = pNode;
219    CFX_WideString name = CFX_WideString(pName, nLength);
220    pNode = _Lookup(pLast, name);
221    name_extractor.GetNext(pName, nLength);
222  }
223  return pNode;
224}
225CPDF_InterForm::CPDF_InterForm(CPDF_Document* pDocument, FX_BOOL bGenerateAP)
226    : CFX_PrivateData(),
227      m_pDocument(pDocument),
228      m_bGenerateAP(bGenerateAP),
229      m_pFormDict(nullptr),
230      m_pFieldTree(new CFieldTree),
231      m_pFormNotify(nullptr),
232      m_bUpdated(FALSE) {
233  CPDF_Dictionary* pRoot = m_pDocument->GetRoot();
234  if (!pRoot)
235    return;
236
237  m_pFormDict = pRoot->GetDict("AcroForm");
238  if (!m_pFormDict)
239    return;
240
241  CPDF_Array* pFields = m_pFormDict->GetArray("Fields");
242  if (!pFields)
243    return;
244
245  int count = pFields->GetCount();
246  for (int i = 0; i < count; i++) {
247    LoadField(pFields->GetDict(i));
248  }
249}
250
251CPDF_InterForm::~CPDF_InterForm() {
252  for (auto it : m_ControlMap)
253    delete it.second;
254
255  int nCount = m_pFieldTree->m_Root.CountFields();
256  for (int i = 0; i < nCount; ++i) {
257    delete m_pFieldTree->m_Root.GetField(i);
258  }
259}
260
261FX_BOOL CPDF_InterForm::m_bUpdateAP = TRUE;
262FX_BOOL CPDF_InterForm::UpdatingAPEnabled() {
263  return m_bUpdateAP;
264}
265void CPDF_InterForm::EnableUpdateAP(FX_BOOL bUpdateAP) {
266  m_bUpdateAP = bUpdateAP;
267}
268CFX_ByteString CPDF_InterForm::GenerateNewResourceName(
269    const CPDF_Dictionary* pResDict,
270    const FX_CHAR* csType,
271    int iMinLen,
272    const FX_CHAR* csPrefix) {
273  CFX_ByteString csStr = csPrefix;
274  CFX_ByteString csBType = csType;
275  if (csStr.IsEmpty()) {
276    if (csBType == "ExtGState") {
277      csStr = "GS";
278    } else if (csBType == "ColorSpace") {
279      csStr = "CS";
280    } else if (csBType == "Font") {
281      csStr = "ZiTi";
282    } else {
283      csStr = "Res";
284    }
285  }
286  CFX_ByteString csTmp = csStr;
287  int iCount = csStr.GetLength();
288  int m = 0;
289  if (iMinLen > 0) {
290    csTmp = "";
291    while (m < iMinLen && m < iCount) {
292      csTmp += csStr[m++];
293    }
294    while (m < iMinLen) {
295      csTmp += '0' + m % 10;
296      m++;
297    }
298  } else {
299    m = iCount;
300  }
301  if (!pResDict) {
302    return csTmp;
303  }
304  CPDF_Dictionary* pDict = pResDict->GetDict(csType);
305  if (!pDict) {
306    return csTmp;
307  }
308  int num = 0;
309  CFX_ByteString bsNum;
310  while (TRUE) {
311    if (!pDict->KeyExist(csTmp + bsNum)) {
312      return csTmp + bsNum;
313    }
314    if (m < iCount) {
315      csTmp += csStr[m++];
316    } else {
317      bsNum.Format("%d", num++);
318    }
319    m++;
320  }
321  return csTmp;
322}
323#if _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_
324typedef struct _PDF_FONTDATA {
325  FX_BOOL bFind;
326  LOGFONTA lf;
327} PDF_FONTDATA, FAR* LPDF_FONTDATA;
328static int CALLBACK EnumFontFamExProc(ENUMLOGFONTEXA* lpelfe,
329                                      NEWTEXTMETRICEX* lpntme,
330                                      DWORD FontType,
331                                      LPARAM lParam) {
332  if (FontType != 0x004 || strchr(lpelfe->elfLogFont.lfFaceName, '@')) {
333    return 1;
334  }
335  LPDF_FONTDATA pData = (LPDF_FONTDATA)lParam;
336  memcpy(&pData->lf, &lpelfe->elfLogFont, sizeof(LOGFONTA));
337  pData->bFind = TRUE;
338  return 0;
339}
340static FX_BOOL RetrieveSpecificFont(LOGFONTA& lf) {
341  PDF_FONTDATA fd;
342  memset(&fd, 0, sizeof(PDF_FONTDATA));
343  HDC hDC = ::GetDC(NULL);
344  EnumFontFamiliesExA(hDC, &lf, (FONTENUMPROCA)EnumFontFamExProc, (LPARAM)&fd,
345                      0);
346  ::ReleaseDC(NULL, hDC);
347  if (fd.bFind) {
348    memcpy(&lf, &fd.lf, sizeof(LOGFONTA));
349  }
350  return fd.bFind;
351}
352static FX_BOOL RetrieveSpecificFont(uint8_t charSet,
353                                    uint8_t pitchAndFamily,
354                                    LPCSTR pcsFontName,
355                                    LOGFONTA& lf) {
356  memset(&lf, 0, sizeof(LOGFONTA));
357  lf.lfCharSet = charSet;
358  lf.lfPitchAndFamily = pitchAndFamily;
359  if (pcsFontName) {
360    strcpy(lf.lfFaceName, pcsFontName);
361  }
362  return RetrieveSpecificFont(lf);
363}
364#ifdef PDF_ENABLE_XFA
365static FX_BOOL RetrieveStockFont(int iFontObject,
366                                 uint8_t charSet,
367                                 LOGFONTA& lf) {
368  HFONT hFont = (HFONT)::GetStockObject(iFontObject);
369  if (hFont != NULL) {
370    memset(&lf, 0, sizeof(LOGFONTA));
371    int iRet = ::GetObject(hFont, sizeof(LOGFONTA), &lf);
372    if (iRet > 0 && (lf.lfCharSet == charSet || charSet == 255)) {
373      return RetrieveSpecificFont(lf);
374    }
375  }
376  return FALSE;
377}
378#endif  // PDF_ENABLE_XFA
379#endif  // _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_
380
381CPDF_Font* CPDF_InterForm::AddStandardFont(CPDF_Document* pDocument,
382                                           CFX_ByteString csFontName) {
383  if (!pDocument || csFontName.IsEmpty())
384    return nullptr;
385
386  if (csFontName == "ZapfDingbats")
387    return pDocument->AddStandardFont(csFontName.c_str(), nullptr);
388
389  CPDF_FontEncoding encoding(PDFFONT_ENCODING_WINANSI);
390  return pDocument->AddStandardFont(csFontName.c_str(), &encoding);
391}
392
393CFX_ByteString CPDF_InterForm::GetNativeFont(uint8_t charSet, void* pLogFont) {
394  CFX_ByteString csFontName;
395#if _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_
396  LOGFONTA lf;
397  FX_BOOL bRet;
398  if (charSet == ANSI_CHARSET) {
399    csFontName = "Helvetica";
400    return csFontName;
401  }
402  bRet = FALSE;
403  if (charSet == SHIFTJIS_CHARSET) {
404    bRet = RetrieveSpecificFont(charSet, DEFAULT_PITCH | FF_DONTCARE,
405                                "MS Mincho", lf);
406  } else if (charSet == GB2312_CHARSET) {
407    bRet = RetrieveSpecificFont(charSet, DEFAULT_PITCH | FF_DONTCARE, "SimSun",
408                                lf);
409  } else if (charSet == CHINESEBIG5_CHARSET) {
410    bRet = RetrieveSpecificFont(charSet, DEFAULT_PITCH | FF_DONTCARE, "MingLiU",
411                                lf);
412  }
413  if (!bRet) {
414    bRet = RetrieveSpecificFont(charSet, DEFAULT_PITCH | FF_DONTCARE,
415                                "Arial Unicode MS", lf);
416  }
417  if (!bRet) {
418    bRet = RetrieveSpecificFont(charSet, DEFAULT_PITCH | FF_DONTCARE,
419                                "Microsoft Sans Serif", lf);
420  }
421  if (!bRet) {
422    bRet = RetrieveSpecificFont(charSet, DEFAULT_PITCH | FF_DONTCARE, NULL, lf);
423  }
424  if (bRet) {
425    if (pLogFont) {
426      memcpy(pLogFont, &lf, sizeof(LOGFONTA));
427    }
428    csFontName = lf.lfFaceName;
429    return csFontName;
430  }
431#endif
432  return csFontName;
433}
434CFX_ByteString CPDF_InterForm::GetNativeFont(void* pLogFont) {
435#if _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_
436  uint8_t charSet = GetNativeCharSet();
437  return GetNativeFont(charSet, pLogFont);
438#else
439  return CFX_ByteString();
440#endif
441}
442uint8_t CPDF_InterForm::GetNativeCharSet() {
443#if _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_
444  uint8_t charSet = ANSI_CHARSET;
445  UINT iCodePage = ::GetACP();
446  switch (iCodePage) {
447    case 932:
448      charSet = SHIFTJIS_CHARSET;
449      break;
450    case 936:
451      charSet = GB2312_CHARSET;
452      break;
453    case 950:
454      charSet = CHINESEBIG5_CHARSET;
455      break;
456    case 1252:
457      charSet = ANSI_CHARSET;
458      break;
459    case 874:
460      charSet = THAI_CHARSET;
461      break;
462    case 949:
463      charSet = HANGUL_CHARSET;
464      break;
465    case 1200:
466      charSet = ANSI_CHARSET;
467      break;
468    case 1250:
469      charSet = EASTEUROPE_CHARSET;
470      break;
471    case 1251:
472      charSet = RUSSIAN_CHARSET;
473      break;
474    case 1253:
475      charSet = GREEK_CHARSET;
476      break;
477    case 1254:
478      charSet = TURKISH_CHARSET;
479      break;
480    case 1255:
481      charSet = HEBREW_CHARSET;
482      break;
483    case 1256:
484      charSet = ARABIC_CHARSET;
485      break;
486    case 1257:
487      charSet = BALTIC_CHARSET;
488      break;
489    case 1258:
490      charSet = VIETNAMESE_CHARSET;
491      break;
492    case 1361:
493      charSet = JOHAB_CHARSET;
494      break;
495  }
496  return charSet;
497#else
498  return 0;
499#endif
500}
501
502CPDF_Font* CPDF_InterForm::AddNativeFont(uint8_t charSet,
503                                         CPDF_Document* pDocument) {
504  if (!pDocument)
505    return nullptr;
506
507#if _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_
508  LOGFONTA lf;
509  CFX_ByteString csFontName = GetNativeFont(charSet, &lf);
510  if (!csFontName.IsEmpty()) {
511    if (csFontName == "Helvetica")
512      return AddStandardFont(pDocument, csFontName);
513    return pDocument->AddWindowsFont(&lf, FALSE, TRUE);
514  }
515#endif
516  return nullptr;
517}
518
519CPDF_Font* CPDF_InterForm::AddNativeFont(CPDF_Document* pDocument) {
520  return pDocument ? AddNativeFont(GetNativeCharSet(), pDocument) : nullptr;
521}
522
523FX_BOOL CPDF_InterForm::ValidateFieldName(
524    CFX_WideString& csNewFieldName,
525    int iType,
526    const CPDF_FormField* pExcludedField,
527    const CPDF_FormControl* pExcludedControl) {
528  if (csNewFieldName.IsEmpty()) {
529    return FALSE;
530  }
531  int iPos = 0;
532  int iLength = csNewFieldName.GetLength();
533  CFX_WideString csSub;
534  while (TRUE) {
535    while (iPos < iLength &&
536           (csNewFieldName[iPos] == L'.' || csNewFieldName[iPos] == L' ')) {
537      iPos++;
538    }
539    if (iPos < iLength && !csSub.IsEmpty()) {
540      csSub += L'.';
541    }
542    while (iPos < iLength && csNewFieldName[iPos] != L'.') {
543      csSub += csNewFieldName[iPos++];
544    }
545    for (int i = csSub.GetLength() - 1; i > -1; i--) {
546      if (csSub[i] == L' ' || csSub[i] == L'.') {
547        csSub.SetAt(i, L'\0');
548      } else {
549        break;
550      }
551    }
552    FX_DWORD dwCount = m_pFieldTree->m_Root.CountFields();
553    for (FX_DWORD m = 0; m < dwCount; m++) {
554      CPDF_FormField* pField = m_pFieldTree->m_Root.GetField(m);
555      if (!pField) {
556        continue;
557      }
558      if (pField == pExcludedField) {
559        if (pExcludedControl) {
560          if (pField->CountControls() < 2) {
561            continue;
562          }
563        } else {
564          continue;
565        }
566      }
567      CFX_WideString csFullName = pField->GetFullName();
568      int iRet = CompareFieldName(csSub, csFullName);
569      if (iRet == 1) {
570        if (pField->GetFieldType() != iType) {
571          return FALSE;
572        }
573      } else if (iRet == 2 && csSub == csNewFieldName) {
574        if (csFullName[iPos] == L'.') {
575          return FALSE;
576        }
577      } else if (iRet == 3 && csSub == csNewFieldName) {
578        if (csNewFieldName[csFullName.GetLength()] == L'.') {
579          return FALSE;
580        }
581      }
582    }
583    if (iPos >= iLength) {
584      break;
585    }
586  }
587  if (csSub.IsEmpty()) {
588    return FALSE;
589  }
590  csNewFieldName = csSub;
591  return TRUE;
592}
593FX_BOOL CPDF_InterForm::ValidateFieldName(CFX_WideString& csNewFieldName,
594                                          int iType) {
595  return ValidateFieldName(csNewFieldName, iType, NULL, NULL);
596}
597FX_BOOL CPDF_InterForm::ValidateFieldName(const CPDF_FormField* pField,
598                                          CFX_WideString& csNewFieldName) {
599  return pField && !csNewFieldName.IsEmpty() &&
600         ValidateFieldName(csNewFieldName,
601                           ((CPDF_FormField*)pField)->GetFieldType(), pField,
602                           NULL);
603}
604FX_BOOL CPDF_InterForm::ValidateFieldName(const CPDF_FormControl* pControl,
605                                          CFX_WideString& csNewFieldName) {
606  if (!pControl || csNewFieldName.IsEmpty()) {
607    return FALSE;
608  }
609  CPDF_FormField* pField = ((CPDF_FormControl*)pControl)->GetField();
610  return ValidateFieldName(csNewFieldName, pField->GetFieldType(), pField,
611                           pControl);
612}
613int CPDF_InterForm::CompareFieldName(const CFX_ByteString& name1,
614                                     const CFX_ByteString& name2) {
615  const FX_CHAR* ptr1 = name1;
616  const FX_CHAR* ptr2 = name2;
617  if (name1.GetLength() == name2.GetLength()) {
618    return name1 == name2 ? 1 : 0;
619  }
620  int i = 0;
621  while (ptr1[i] == ptr2[i]) {
622    i++;
623  }
624  if (i == name1.GetLength()) {
625    return 2;
626  }
627  if (i == name2.GetLength()) {
628    return 3;
629  }
630  return 0;
631}
632int CPDF_InterForm::CompareFieldName(const CFX_WideString& name1,
633                                     const CFX_WideString& name2) {
634  const FX_WCHAR* ptr1 = name1.c_str();
635  const FX_WCHAR* ptr2 = name2.c_str();
636  if (name1.GetLength() == name2.GetLength()) {
637    return name1 == name2 ? 1 : 0;
638  }
639  int i = 0;
640  while (ptr1[i] == ptr2[i]) {
641    i++;
642  }
643  if (i == name1.GetLength()) {
644    return 2;
645  }
646  if (i == name2.GetLength()) {
647    return 3;
648  }
649  return 0;
650}
651FX_DWORD CPDF_InterForm::CountFields(const CFX_WideString& csFieldName) {
652  if (csFieldName.IsEmpty()) {
653    return (FX_DWORD)m_pFieldTree->m_Root.CountFields();
654  }
655  CFieldTree::_Node* pNode = m_pFieldTree->FindNode(csFieldName);
656  return pNode ? pNode->CountFields() : 0;
657}
658CPDF_FormField* CPDF_InterForm::GetField(FX_DWORD index,
659                                         const CFX_WideString& csFieldName) {
660  if (csFieldName == L"") {
661    return m_pFieldTree->m_Root.GetField(index);
662  }
663  CFieldTree::_Node* pNode = m_pFieldTree->FindNode(csFieldName);
664  return pNode ? pNode->GetField(index) : nullptr;
665}
666void CPDF_InterForm::GetAllFieldNames(CFX_WideStringArray& allFieldNames) {
667  allFieldNames.RemoveAll();
668  int nCount = m_pFieldTree->m_Root.CountFields();
669  for (int i = 0; i < nCount; i++) {
670    CPDF_FormField* pField = m_pFieldTree->m_Root.GetField(i);
671    if (pField) {
672      CFX_WideString full_name = GetFullName(pField->GetFieldDict());
673      allFieldNames.Add(full_name);
674    }
675  }
676}
677
678CPDF_FormField* CPDF_InterForm::GetFieldByDict(
679    CPDF_Dictionary* pFieldDict) const {
680  if (!pFieldDict) {
681    return NULL;
682  }
683  CFX_WideString csWName = GetFullName(pFieldDict);
684  return m_pFieldTree->GetField(csWName);
685}
686
687CPDF_FormControl* CPDF_InterForm::GetControlAtPoint(CPDF_Page* pPage,
688                                                    FX_FLOAT pdf_x,
689                                                    FX_FLOAT pdf_y,
690                                                    int* z_order) const {
691  CPDF_Array* pAnnotList = pPage->m_pFormDict->GetArray("Annots");
692  if (!pAnnotList)
693    return nullptr;
694
695  for (FX_DWORD i = pAnnotList->GetCount(); i > 0; --i) {
696    FX_DWORD annot_index = i - 1;
697    CPDF_Dictionary* pAnnot = pAnnotList->GetDict(annot_index);
698    if (!pAnnot)
699      continue;
700
701    const auto it = m_ControlMap.find(pAnnot);
702    if (it == m_ControlMap.end())
703      continue;
704
705    CPDF_FormControl* pControl = it->second;
706    CFX_FloatRect rect = pControl->GetRect();
707    if (!rect.Contains(pdf_x, pdf_y))
708      continue;
709
710    if (z_order)
711      *z_order = annot_index;
712    return pControl;
713  }
714  return nullptr;
715}
716
717CPDF_FormControl* CPDF_InterForm::GetControlByDict(
718    const CPDF_Dictionary* pWidgetDict) const {
719  const auto it = m_ControlMap.find(pWidgetDict);
720  return it != m_ControlMap.end() ? it->second : nullptr;
721}
722
723FX_BOOL CPDF_InterForm::NeedConstructAP() {
724  return m_pFormDict && m_pFormDict->GetBoolean("NeedAppearances");
725}
726void CPDF_InterForm::NeedConstructAP(FX_BOOL bNeedAP) {
727  if (!m_pFormDict) {
728    InitInterFormDict(m_pFormDict, m_pDocument);
729  }
730  m_pFormDict->SetAtBoolean("NeedAppearances", bNeedAP);
731  m_bGenerateAP = bNeedAP;
732}
733int CPDF_InterForm::CountFieldsInCalculationOrder() {
734  if (!m_pFormDict) {
735    return 0;
736  }
737  CPDF_Array* pArray = m_pFormDict->GetArray("CO");
738  return pArray ? pArray->GetCount() : 0;
739}
740CPDF_FormField* CPDF_InterForm::GetFieldInCalculationOrder(int index) {
741  if (!m_pFormDict || index < 0) {
742    return NULL;
743  }
744  CPDF_Array* pArray = m_pFormDict->GetArray("CO");
745  if (!pArray) {
746    return NULL;
747  }
748  if (CPDF_Dictionary* pElement =
749          ToDictionary(pArray->GetElementValue(index))) {
750    return GetFieldByDict(pElement);
751  }
752  return NULL;
753}
754int CPDF_InterForm::FindFieldInCalculationOrder(const CPDF_FormField* pField) {
755  if (!m_pFormDict || !pField) {
756    return -1;
757  }
758  CPDF_Array* pArray = m_pFormDict->GetArray("CO");
759  if (!pArray) {
760    return -1;
761  }
762  for (FX_DWORD i = 0; i < pArray->GetCount(); i++) {
763    CPDF_Object* pElement = pArray->GetElementValue(i);
764    if (pElement == pField->m_pDict) {
765      return i;
766    }
767  }
768  return -1;
769}
770FX_DWORD CPDF_InterForm::CountFormFonts() {
771  return CountInterFormFonts(m_pFormDict);
772}
773CPDF_Font* CPDF_InterForm::GetFormFont(FX_DWORD index,
774                                       CFX_ByteString& csNameTag) {
775  return GetInterFormFont(m_pFormDict, m_pDocument, index, csNameTag);
776}
777CPDF_Font* CPDF_InterForm::GetFormFont(CFX_ByteString csNameTag) {
778  return GetInterFormFont(m_pFormDict, m_pDocument, csNameTag);
779}
780CPDF_Font* CPDF_InterForm::GetFormFont(CFX_ByteString csFontName,
781                                       CFX_ByteString& csNameTag) {
782  return GetInterFormFont(m_pFormDict, m_pDocument, csFontName, csNameTag);
783}
784CPDF_Font* CPDF_InterForm::GetNativeFormFont(uint8_t charSet,
785                                             CFX_ByteString& csNameTag) {
786  return GetNativeInterFormFont(m_pFormDict, m_pDocument, charSet, csNameTag);
787}
788CPDF_Font* CPDF_InterForm::GetNativeFormFont(CFX_ByteString& csNameTag) {
789  return GetNativeInterFormFont(m_pFormDict, m_pDocument, csNameTag);
790}
791FX_BOOL CPDF_InterForm::FindFormFont(const CPDF_Font* pFont,
792                                     CFX_ByteString& csNameTag) {
793  return FindInterFormFont(m_pFormDict, pFont, csNameTag);
794}
795FX_BOOL CPDF_InterForm::FindFormFont(CFX_ByteString csFontName,
796                                     CPDF_Font*& pFont,
797                                     CFX_ByteString& csNameTag) {
798  return FindInterFormFont(m_pFormDict, m_pDocument, csFontName, pFont,
799                           csNameTag);
800}
801void CPDF_InterForm::AddFormFont(const CPDF_Font* pFont,
802                                 CFX_ByteString& csNameTag) {
803  AddInterFormFont(m_pFormDict, m_pDocument, pFont, csNameTag);
804  m_bUpdated = TRUE;
805}
806CPDF_Font* CPDF_InterForm::AddNativeFormFont(uint8_t charSet,
807                                             CFX_ByteString& csNameTag) {
808  m_bUpdated = TRUE;
809  return AddNativeInterFormFont(m_pFormDict, m_pDocument, charSet, csNameTag);
810}
811CPDF_Font* CPDF_InterForm::AddNativeFormFont(CFX_ByteString& csNameTag) {
812  m_bUpdated = TRUE;
813  return AddNativeInterFormFont(m_pFormDict, m_pDocument, csNameTag);
814}
815void CPDF_InterForm::RemoveFormFont(const CPDF_Font* pFont) {
816  m_bUpdated = TRUE;
817  RemoveInterFormFont(m_pFormDict, pFont);
818}
819void CPDF_InterForm::RemoveFormFont(CFX_ByteString csNameTag) {
820  m_bUpdated = TRUE;
821  RemoveInterFormFont(m_pFormDict, csNameTag);
822}
823CPDF_DefaultAppearance CPDF_InterForm::GetDefaultAppearance() {
824  CFX_ByteString csDA;
825  if (!m_pFormDict) {
826    return csDA;
827  }
828  csDA = m_pFormDict->GetString("DA");
829  return csDA;
830}
831CPDF_Font* CPDF_InterForm::GetDefaultFormFont() {
832  return GetDefaultInterFormFont(m_pFormDict, m_pDocument);
833}
834int CPDF_InterForm::GetFormAlignment() {
835  return m_pFormDict ? m_pFormDict->GetInteger("Q", 0) : 0;
836}
837
838bool CPDF_InterForm::ResetForm(const std::vector<CPDF_FormField*>& fields,
839                               bool bIncludeOrExclude,
840                               bool bNotify) {
841  if (bNotify && m_pFormNotify && m_pFormNotify->BeforeFormReset(this) < 0)
842    return false;
843
844  int nCount = m_pFieldTree->m_Root.CountFields();
845  for (int i = 0; i < nCount; ++i) {
846    CPDF_FormField* pField = m_pFieldTree->m_Root.GetField(i);
847    if (!pField)
848      continue;
849
850    if (bIncludeOrExclude == pdfium::ContainsValue(fields, pField))
851      pField->ResetField(bNotify);
852  }
853  if (bNotify && m_pFormNotify)
854    m_pFormNotify->AfterFormReset(this);
855  return true;
856}
857
858bool CPDF_InterForm::ResetForm(bool bNotify) {
859  if (bNotify && m_pFormNotify && m_pFormNotify->BeforeFormReset(this) < 0)
860    return false;
861
862  int nCount = m_pFieldTree->m_Root.CountFields();
863  for (int i = 0; i < nCount; ++i) {
864    CPDF_FormField* pField = m_pFieldTree->m_Root.GetField(i);
865    if (!pField)
866      continue;
867
868    pField->ResetField(bNotify);
869  }
870  if (bNotify && m_pFormNotify)
871    m_pFormNotify->AfterFormReset(this);
872  return true;
873}
874
875void CPDF_InterForm::LoadField(CPDF_Dictionary* pFieldDict, int nLevel) {
876  if (nLevel > nMaxRecursion) {
877    return;
878  }
879  if (!pFieldDict) {
880    return;
881  }
882  FX_DWORD dwParentObjNum = pFieldDict->GetObjNum();
883  CPDF_Array* pKids = pFieldDict->GetArray("Kids");
884  if (!pKids) {
885    AddTerminalField(pFieldDict);
886    return;
887  }
888  CPDF_Dictionary* pFirstKid = pKids->GetDict(0);
889  if (!pFirstKid) {
890    return;
891  }
892  if (pFirstKid->KeyExist("T") || pFirstKid->KeyExist("Kids")) {
893    for (FX_DWORD i = 0; i < pKids->GetCount(); i++) {
894      CPDF_Dictionary* pChildDict = pKids->GetDict(i);
895      if (pChildDict) {
896        if (pChildDict->GetObjNum() != dwParentObjNum) {
897          LoadField(pChildDict, nLevel + 1);
898        }
899      }
900    }
901  } else {
902    AddTerminalField(pFieldDict);
903  }
904}
905FX_BOOL CPDF_InterForm::HasXFAForm() const {
906  return m_pFormDict && m_pFormDict->GetArray("XFA");
907}
908void CPDF_InterForm::FixPageFields(const CPDF_Page* pPage) {
909  CPDF_Dictionary* pPageDict = pPage->m_pFormDict;
910  if (!pPageDict) {
911    return;
912  }
913  CPDF_Array* pAnnots = pPageDict->GetArray("Annots");
914  if (!pAnnots) {
915    return;
916  }
917  int iAnnotCount = pAnnots->GetCount();
918  for (int i = 0; i < iAnnotCount; i++) {
919    CPDF_Dictionary* pAnnot = pAnnots->GetDict(i);
920    if (pAnnot && pAnnot->GetString("Subtype") == "Widget") {
921      LoadField(pAnnot);
922    }
923  }
924}
925CPDF_FormField* CPDF_InterForm::AddTerminalField(CPDF_Dictionary* pFieldDict) {
926  if (!pFieldDict->KeyExist("T")) {
927    return NULL;
928  }
929  CPDF_Dictionary* pDict = pFieldDict;
930  CFX_WideString csWName = GetFullName(pFieldDict);
931  if (csWName.IsEmpty()) {
932    return NULL;
933  }
934  CPDF_FormField* pField = NULL;
935  pField = m_pFieldTree->GetField(csWName);
936  if (!pField) {
937    CPDF_Dictionary* pParent = pFieldDict;
938    if (!pFieldDict->KeyExist("T") &&
939        pFieldDict->GetString("Subtype") == "Widget") {
940      pParent = pFieldDict->GetDict("Parent");
941      if (!pParent) {
942        pParent = pFieldDict;
943      }
944    }
945    if (pParent && pParent != pFieldDict && !pParent->KeyExist("FT")) {
946      if (pFieldDict->KeyExist("FT")) {
947        CPDF_Object* pFTValue = pFieldDict->GetElementValue("FT");
948        if (pFTValue) {
949          pParent->SetAt("FT", pFTValue->Clone());
950        }
951      }
952      if (pFieldDict->KeyExist("Ff")) {
953        CPDF_Object* pFfValue = pFieldDict->GetElementValue("Ff");
954        if (pFfValue) {
955          pParent->SetAt("Ff", pFfValue->Clone());
956        }
957      }
958    }
959    pField = new CPDF_FormField(this, pParent);
960    CPDF_Object* pTObj = pDict->GetElement("T");
961    if (ToReference(pTObj)) {
962      CPDF_Object* pClone = pTObj->Clone(TRUE);
963      if (pClone)
964        pDict->SetAt("T", pClone);
965      else
966        pDict->SetAtName("T", "");
967    }
968    m_pFieldTree->SetField(csWName, pField);
969  }
970  CPDF_Array* pKids = pFieldDict->GetArray("Kids");
971  if (!pKids) {
972    if (pFieldDict->GetString("Subtype") == "Widget") {
973      AddControl(pField, pFieldDict);
974    }
975  } else {
976    for (FX_DWORD i = 0; i < pKids->GetCount(); i++) {
977      CPDF_Dictionary* pKid = pKids->GetDict(i);
978      if (!pKid) {
979        continue;
980      }
981      if (pKid->GetString("Subtype") != "Widget") {
982        continue;
983      }
984      AddControl(pField, pKid);
985    }
986  }
987  return pField;
988}
989CPDF_FormControl* CPDF_InterForm::AddControl(const CPDF_FormField* pField,
990                                             CPDF_Dictionary* pWidgetDict) {
991  const auto it = m_ControlMap.find(pWidgetDict);
992  if (it != m_ControlMap.end())
993    return it->second;
994
995  CPDF_FormControl* pControl =
996      new CPDF_FormControl((CPDF_FormField*)pField, pWidgetDict);
997  m_ControlMap[pWidgetDict] = pControl;
998  ((CPDF_FormField*)pField)->m_ControlList.Add(pControl);
999  return pControl;
1000}
1001
1002CPDF_FormField* CPDF_InterForm::CheckRequiredFields(
1003    const std::vector<CPDF_FormField*>* fields,
1004    bool bIncludeOrExclude) const {
1005  int nCount = m_pFieldTree->m_Root.CountFields();
1006  for (int i = 0; i < nCount; ++i) {
1007    CPDF_FormField* pField = m_pFieldTree->m_Root.GetField(i);
1008    if (!pField)
1009      continue;
1010
1011    int32_t iType = pField->GetType();
1012    if (iType == CPDF_FormField::PushButton ||
1013        iType == CPDF_FormField::CheckBox || iType == CPDF_FormField::ListBox) {
1014      continue;
1015    }
1016    FX_DWORD dwFlags = pField->GetFieldFlags();
1017    // TODO(thestig): Look up these magic numbers and add constants for them.
1018    if (dwFlags & 0x04)
1019      continue;
1020
1021    bool bFind = true;
1022    if (fields)
1023      bFind = pdfium::ContainsValue(*fields, pField);
1024    if (bIncludeOrExclude == bFind) {
1025      CPDF_Dictionary* pFieldDict = pField->m_pDict;
1026      if ((dwFlags & 0x02) != 0 && pFieldDict->GetString("V").IsEmpty()) {
1027        return pField;
1028      }
1029    }
1030  }
1031  return nullptr;
1032}
1033
1034CFDF_Document* CPDF_InterForm::ExportToFDF(const CFX_WideStringC& pdf_path,
1035                                           bool bSimpleFileSpec) const {
1036  std::vector<CPDF_FormField*> fields;
1037  int nCount = m_pFieldTree->m_Root.CountFields();
1038  for (int i = 0; i < nCount; ++i)
1039    fields.push_back(m_pFieldTree->m_Root.GetField(i));
1040  return ExportToFDF(pdf_path, fields, true, bSimpleFileSpec);
1041}
1042
1043CFDF_Document* CPDF_InterForm::ExportToFDF(
1044    const CFX_WideStringC& pdf_path,
1045    const std::vector<CPDF_FormField*>& fields,
1046    bool bIncludeOrExclude,
1047    bool bSimpleFileSpec) const {
1048  CFDF_Document* pDoc = CFDF_Document::CreateNewDoc();
1049  if (!pDoc) {
1050    return NULL;
1051  }
1052  CPDF_Dictionary* pMainDict = pDoc->GetRoot()->GetDict("FDF");
1053  if (!pdf_path.IsEmpty()) {
1054    if (bSimpleFileSpec) {
1055      CFX_WideString wsFilePath = FILESPEC_EncodeFileName(pdf_path);
1056      pMainDict->SetAtString("F", CFX_ByteString::FromUnicode(wsFilePath));
1057      pMainDict->SetAtString("UF", PDF_EncodeText(wsFilePath));
1058    } else {
1059      CPDF_FileSpec filespec;
1060      filespec.SetFileName(pdf_path);
1061      pMainDict->SetAt("F", static_cast<CPDF_Object*>(filespec));
1062    }
1063  }
1064  CPDF_Array* pFields = new CPDF_Array;
1065  pMainDict->SetAt("Fields", pFields);
1066  int nCount = m_pFieldTree->m_Root.CountFields();
1067  for (int i = 0; i < nCount; i++) {
1068    CPDF_FormField* pField = m_pFieldTree->m_Root.GetField(i);
1069    if (!pField || pField->GetType() == CPDF_FormField::PushButton) {
1070      continue;
1071    }
1072    FX_DWORD dwFlags = pField->GetFieldFlags();
1073    if (dwFlags & 0x04)
1074      continue;
1075
1076    if (bIncludeOrExclude == pdfium::ContainsValue(fields, pField)) {
1077      if ((dwFlags & 0x02) != 0 && pField->m_pDict->GetString("V").IsEmpty())
1078        continue;
1079
1080      CFX_WideString fullname = GetFullName(pField->GetFieldDict());
1081      CPDF_Dictionary* pFieldDict = new CPDF_Dictionary;
1082      pFieldDict->SetAt("T", new CPDF_String(fullname));
1083      if (pField->GetType() == CPDF_FormField::CheckBox ||
1084          pField->GetType() == CPDF_FormField::RadioButton) {
1085        CFX_WideString csExport = pField->GetCheckValue(FALSE);
1086        CFX_ByteString csBExport = PDF_EncodeText(csExport);
1087        CPDF_Object* pOpt = FPDF_GetFieldAttr(pField->m_pDict, "Opt");
1088        if (pOpt)
1089          pFieldDict->SetAtString("V", csBExport);
1090        else
1091          pFieldDict->SetAtName("V", csBExport);
1092      } else {
1093        CPDF_Object* pV = FPDF_GetFieldAttr(pField->m_pDict, "V");
1094        if (pV)
1095          pFieldDict->SetAt("V", pV->Clone(TRUE));
1096      }
1097      pFields->Add(pFieldDict);
1098    }
1099  }
1100  return pDoc;
1101}
1102const struct _SupportFieldEncoding {
1103  const FX_CHAR* m_name;
1104  int32_t m_codePage;
1105} g_fieldEncoding[] = {
1106    {"BigFive", 950},
1107    {"GBK", 936},
1108    {"Shift-JIS", 932},
1109    {"UHC", 949},
1110};
1111static void FPDFDOC_FDF_GetFieldValue(CPDF_Dictionary* pFieldDict,
1112                                      CFX_WideString& csValue,
1113                                      CFX_ByteString& bsEncoding) {
1114  CFX_ByteString csBValue = pFieldDict->GetString("V");
1115  int32_t iCount = sizeof(g_fieldEncoding) / sizeof(g_fieldEncoding[0]);
1116  int32_t i = 0;
1117  for (; i < iCount; ++i)
1118    if (bsEncoding == g_fieldEncoding[i].m_name) {
1119      break;
1120    }
1121  if (i < iCount) {
1122    CFX_CharMap* pCharMap =
1123        CFX_CharMap::GetDefaultMapper(g_fieldEncoding[i].m_codePage);
1124    FXSYS_assert(pCharMap);
1125    csValue.ConvertFrom(csBValue, pCharMap);
1126    return;
1127  }
1128  CFX_ByteString csTemp = csBValue.Left(2);
1129  if (csTemp == "\xFF\xFE" || csTemp == "\xFE\xFF") {
1130    csValue = PDF_DecodeText(csBValue);
1131  } else {
1132    csValue = CFX_WideString::FromLocal(csBValue);
1133  }
1134}
1135void CPDF_InterForm::FDF_ImportField(CPDF_Dictionary* pFieldDict,
1136                                     const CFX_WideString& parent_name,
1137                                     FX_BOOL bNotify,
1138                                     int nLevel) {
1139  CFX_WideString name;
1140  if (!parent_name.IsEmpty()) {
1141    name = parent_name + L".";
1142  }
1143  name += pFieldDict->GetUnicodeText("T");
1144  CPDF_Array* pKids = pFieldDict->GetArray("Kids");
1145  if (pKids) {
1146    for (FX_DWORD i = 0; i < pKids->GetCount(); i++) {
1147      CPDF_Dictionary* pKid = pKids->GetDict(i);
1148      if (!pKid) {
1149        continue;
1150      }
1151      if (nLevel <= nMaxRecursion) {
1152        FDF_ImportField(pKid, name, bNotify, nLevel + 1);
1153      }
1154    }
1155    return;
1156  }
1157  if (!pFieldDict->KeyExist("V")) {
1158    return;
1159  }
1160  CPDF_FormField* pField = m_pFieldTree->GetField(name);
1161  if (!pField) {
1162    return;
1163  }
1164  CFX_WideString csWValue;
1165  FPDFDOC_FDF_GetFieldValue(pFieldDict, csWValue, m_bsEncoding);
1166  int iType = pField->GetFieldType();
1167  if (bNotify && m_pFormNotify) {
1168    int iRet = 0;
1169    if (iType == FIELDTYPE_LISTBOX) {
1170      iRet = m_pFormNotify->BeforeSelectionChange(pField, csWValue);
1171    } else if (iType == FIELDTYPE_COMBOBOX || iType == FIELDTYPE_TEXTFIELD) {
1172      iRet = m_pFormNotify->BeforeValueChange(pField, csWValue);
1173    }
1174    if (iRet < 0) {
1175      return;
1176    }
1177  }
1178  CFX_ByteArray statusArray;
1179  if (iType == FIELDTYPE_CHECKBOX || iType == FIELDTYPE_RADIOBUTTON) {
1180    SaveCheckedFieldStatus(pField, statusArray);
1181  }
1182  pField->SetValue(csWValue);
1183  CPDF_FormField::Type eType = pField->GetType();
1184  if ((eType == CPDF_FormField::ListBox || eType == CPDF_FormField::ComboBox) &&
1185      pFieldDict->KeyExist("Opt")) {
1186    pField->m_pDict->SetAt("Opt",
1187                           pFieldDict->GetElementValue("Opt")->Clone(TRUE));
1188  }
1189  if (bNotify && m_pFormNotify) {
1190    if (iType == FIELDTYPE_CHECKBOX || iType == FIELDTYPE_RADIOBUTTON) {
1191      m_pFormNotify->AfterCheckedStatusChange(pField, statusArray);
1192    } else if (iType == FIELDTYPE_LISTBOX) {
1193      m_pFormNotify->AfterSelectionChange(pField);
1194    } else if (iType == FIELDTYPE_COMBOBOX || iType == FIELDTYPE_TEXTFIELD) {
1195      m_pFormNotify->AfterValueChange(pField);
1196    }
1197  }
1198  if (CPDF_InterForm::m_bUpdateAP) {
1199    pField->UpdateAP(NULL);
1200  }
1201}
1202FX_BOOL CPDF_InterForm::ImportFromFDF(const CFDF_Document* pFDF,
1203                                      FX_BOOL bNotify) {
1204  if (!pFDF) {
1205    return FALSE;
1206  }
1207  CPDF_Dictionary* pMainDict = pFDF->GetRoot()->GetDict("FDF");
1208  if (!pMainDict) {
1209    return FALSE;
1210  }
1211  CPDF_Array* pFields = pMainDict->GetArray("Fields");
1212  if (!pFields) {
1213    return FALSE;
1214  }
1215  m_bsEncoding = pMainDict->GetString("Encoding");
1216  if (bNotify && m_pFormNotify) {
1217    int iRet = m_pFormNotify->BeforeFormImportData(this);
1218    if (iRet < 0) {
1219      return FALSE;
1220    }
1221  }
1222  for (FX_DWORD i = 0; i < pFields->GetCount(); i++) {
1223    CPDF_Dictionary* pField = pFields->GetDict(i);
1224    if (!pField) {
1225      continue;
1226    }
1227    FDF_ImportField(pField, L"", bNotify);
1228  }
1229  if (bNotify && m_pFormNotify) {
1230    m_pFormNotify->AfterFormImportData(this);
1231  }
1232  return TRUE;
1233}
1234void CPDF_InterForm::SetFormNotify(const CPDF_FormNotify* pNotify) {
1235  m_pFormNotify = (CPDF_FormNotify*)pNotify;
1236}
1237