• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
PDF_FormField_IsUnison(CPDF_FormField * pField)10 FX_BOOL PDF_FormField_IsUnison(CPDF_FormField* pField) {
11   FX_BOOL bUnison = FALSE;
12   if (pField->GetType() == CPDF_FormField::CheckBox) {
13     bUnison = TRUE;
14   } else {
15     FX_DWORD dwFlags = pField->GetFieldFlags();
16     bUnison = ((dwFlags & 0x2000000) != 0);
17   }
18   return bUnison;
19 }
CPDF_FormField(CPDF_InterForm * pForm,CPDF_Dictionary * pDict)20 CPDF_FormField::CPDF_FormField(CPDF_InterForm* pForm, CPDF_Dictionary* pDict) {
21   m_pDict = pDict;
22   m_Type = Unknown;
23   m_pForm = pForm;
24   m_pFont = NULL;
25   m_FontSize = 0;
26   SyncFieldFlags();
27 }
~CPDF_FormField()28 CPDF_FormField::~CPDF_FormField() {}
SyncFieldFlags()29 void CPDF_FormField::SyncFieldFlags() {
30   CFX_ByteString type_name = FPDF_GetFieldAttr(m_pDict, "FT")
31                                  ? FPDF_GetFieldAttr(m_pDict, "FT")->GetString()
32                                  : CFX_ByteString();
33   FX_DWORD flags = FPDF_GetFieldAttr(m_pDict, "Ff")
34                        ? FPDF_GetFieldAttr(m_pDict, "Ff")->GetInteger()
35                        : 0;
36   m_Flags = 0;
37   if (flags & 1) {
38     m_Flags |= FORMFIELD_READONLY;
39   }
40   if (flags & 2) {
41     m_Flags |= FORMFIELD_REQUIRED;
42   }
43   if (flags & 4) {
44     m_Flags |= FORMFIELD_NOEXPORT;
45   }
46   if (type_name == "Btn") {
47     if (flags & 0x8000) {
48       m_Type = RadioButton;
49       if (flags & 0x4000) {
50         m_Flags |= FORMRADIO_NOTOGGLEOFF;
51       }
52       if (flags & 0x2000000) {
53         m_Flags |= FORMRADIO_UNISON;
54       }
55     } else if (flags & 0x10000) {
56       m_Type = PushButton;
57     } else {
58       m_Type = CheckBox;
59     }
60   } else if (type_name == "Tx") {
61     if (flags & 0x100000) {
62       m_Type = File;
63     } else if (flags & 0x2000000) {
64       m_Type = RichText;
65     } else {
66       m_Type = Text;
67       if (flags & 0x1000) {
68         m_Flags |= FORMTEXT_MULTILINE;
69       }
70       if (flags & 0x2000) {
71         m_Flags |= FORMTEXT_PASSWORD;
72       }
73       if (flags & 0x800000) {
74         m_Flags |= FORMTEXT_NOSCROLL;
75       }
76       if (flags & 0x100000) {
77         m_Flags |= FORMTEXT_COMB;
78       }
79     }
80     LoadDA();
81   } else if (type_name == "Ch") {
82     if (flags & 0x20000) {
83       m_Type = ComboBox;
84       if (flags & 0x40000) {
85         m_Flags |= FORMCOMBO_EDIT;
86       }
87     } else {
88       m_Type = ListBox;
89       if (flags & 0x200000) {
90         m_Flags |= FORMLIST_MULTISELECT;
91       }
92     }
93     LoadDA();
94   } else if (type_name == "Sig") {
95     m_Type = Sign;
96   }
97 }
GetFullName()98 CFX_WideString CPDF_FormField::GetFullName() {
99   return ::GetFullName(m_pDict);
100 }
ResetField(FX_BOOL bNotify)101 FX_BOOL CPDF_FormField::ResetField(FX_BOOL bNotify) {
102   switch (m_Type) {
103     case CPDF_FormField::CheckBox:
104     case CPDF_FormField::RadioButton: {
105       CFX_ByteArray statusArray;
106       if (bNotify && m_pForm->m_pFormNotify) {
107         SaveCheckedFieldStatus(this, statusArray);
108       }
109       int iCount = CountControls();
110       if (iCount) {
111         if (PDF_FormField_IsUnison(this)) {
112           for (int i = 0; i < iCount; i++) {
113             CheckControl(i, GetControl(i)->IsDefaultChecked(), FALSE);
114           }
115         } else {
116           for (int i = 0; i < iCount; i++) {
117             CPDF_FormControl* pControl = GetControl(i);
118             FX_BOOL bChecked = pControl->IsDefaultChecked();
119             CheckControl(i, bChecked, FALSE);
120           }
121         }
122       }
123       if (bNotify && m_pForm->m_pFormNotify) {
124         m_pForm->m_pFormNotify->AfterCheckedStatusChange(this, statusArray);
125       }
126     } break;
127     case CPDF_FormField::ComboBox: {
128       CFX_WideString csValue;
129       ClearSelection();
130       int iIndex = GetDefaultSelectedItem();
131       if (iIndex >= 0) {
132         csValue = GetOptionLabel(iIndex);
133       }
134       if (bNotify && m_pForm->m_pFormNotify) {
135         int iRet = m_pForm->m_pFormNotify->BeforeValueChange(this, csValue);
136         if (iRet < 0) {
137           return FALSE;
138         }
139       }
140       SetItemSelection(iIndex, TRUE);
141       if (bNotify && m_pForm->m_pFormNotify) {
142         m_pForm->m_pFormNotify->AfterValueChange(this);
143       }
144     } break;
145     case CPDF_FormField::ListBox: {
146       CFX_WideString csValue;
147       ClearSelection();
148       int iIndex = GetDefaultSelectedItem();
149       if (iIndex >= 0) {
150         csValue = GetOptionLabel(iIndex);
151       }
152       if (bNotify && m_pForm->m_pFormNotify) {
153         int iRet = m_pForm->m_pFormNotify->BeforeSelectionChange(this, csValue);
154         if (iRet < 0) {
155           return FALSE;
156         }
157       }
158       SetItemSelection(iIndex, TRUE);
159       if (bNotify && m_pForm->m_pFormNotify) {
160         m_pForm->m_pFormNotify->AfterSelectionChange(this);
161       }
162     } break;
163     case CPDF_FormField::Text:
164     case CPDF_FormField::RichText:
165     case CPDF_FormField::File:
166     default: {
167       CPDF_Object* pDV = FPDF_GetFieldAttr(m_pDict, "DV");
168       CFX_WideString csDValue;
169       if (pDV) {
170         csDValue = pDV->GetUnicodeText();
171       }
172       CPDF_Object* pV = FPDF_GetFieldAttr(m_pDict, "V");
173       CFX_WideString csValue;
174       if (pV) {
175         csValue = pV->GetUnicodeText();
176       }
177       CPDF_Object* pRV = FPDF_GetFieldAttr(m_pDict, "RV");
178       if (!pRV && (csDValue == csValue)) {
179         return FALSE;
180       }
181       if (bNotify && m_pForm->m_pFormNotify) {
182         int iRet = m_pForm->m_pFormNotify->BeforeValueChange(this, csDValue);
183         if (iRet < 0) {
184           return FALSE;
185         }
186       }
187       if (pDV) {
188         CPDF_Object* pClone = pDV->Clone();
189         if (!pClone) {
190           return FALSE;
191         }
192         m_pDict->SetAt("V", pClone);
193         if (pRV) {
194           CPDF_Object* pCloneR = pDV->Clone();
195           m_pDict->SetAt("RV", pCloneR);
196         }
197       } else {
198         m_pDict->RemoveAt("V");
199         m_pDict->RemoveAt("RV");
200       }
201       if (bNotify && m_pForm->m_pFormNotify) {
202         m_pForm->m_pFormNotify->AfterValueChange(this);
203       }
204       m_pForm->m_bUpdated = TRUE;
205     } break;
206   }
207   return TRUE;
208 }
GetControlIndex(const CPDF_FormControl * pControl)209 int CPDF_FormField::GetControlIndex(const CPDF_FormControl* pControl) {
210   if (!pControl) {
211     return -1;
212   }
213   for (int i = 0; i < m_ControlList.GetSize(); i++) {
214     if (m_ControlList.GetAt(i) == pControl)
215       return i;
216   }
217   return -1;
218 }
GetFieldType()219 int CPDF_FormField::GetFieldType() {
220   switch (m_Type) {
221     case PushButton:
222       return FIELDTYPE_PUSHBUTTON;
223     case CheckBox:
224       return FIELDTYPE_CHECKBOX;
225     case RadioButton:
226       return FIELDTYPE_RADIOBUTTON;
227     case ComboBox:
228       return FIELDTYPE_COMBOBOX;
229     case ListBox:
230       return FIELDTYPE_LISTBOX;
231     case Text:
232     case RichText:
233     case File:
234       return FIELDTYPE_TEXTFIELD;
235     case Sign:
236       return FIELDTYPE_SIGNATURE;
237     default:
238       break;
239   }
240   return FIELDTYPE_UNKNOWN;
241 }
GetAdditionalAction()242 CPDF_AAction CPDF_FormField::GetAdditionalAction() {
243   CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict, "AA");
244   if (!pObj) {
245     return NULL;
246   }
247   return pObj->GetDict();
248 }
GetAlternateName()249 CFX_WideString CPDF_FormField::GetAlternateName() {
250   CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict, "TU");
251   if (!pObj) {
252     return L"";
253   }
254   return pObj->GetUnicodeText();
255 }
GetMappingName()256 CFX_WideString CPDF_FormField::GetMappingName() {
257   CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict, "TM");
258   if (!pObj) {
259     return L"";
260   }
261   return pObj->GetUnicodeText();
262 }
GetFieldFlags()263 FX_DWORD CPDF_FormField::GetFieldFlags() {
264   CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict, "Ff");
265   if (!pObj) {
266     return 0;
267   }
268   return pObj->GetInteger();
269 }
GetDefaultStyle()270 CFX_ByteString CPDF_FormField::GetDefaultStyle() {
271   CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict, "DS");
272   if (!pObj) {
273     return "";
274   }
275   return pObj->GetString();
276 }
GetRichTextString()277 CFX_WideString CPDF_FormField::GetRichTextString() {
278   CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict, "RV");
279   if (!pObj) {
280     return L"";
281   }
282   return pObj->GetUnicodeText();
283 }
GetValue(FX_BOOL bDefault)284 CFX_WideString CPDF_FormField::GetValue(FX_BOOL bDefault) {
285   if (GetType() == CheckBox || GetType() == RadioButton) {
286     return GetCheckValue(bDefault);
287   }
288   CPDF_Object* pValue = FPDF_GetFieldAttr(m_pDict, bDefault ? "DV" : "V");
289   if (!pValue) {
290     if (!bDefault) {
291       if (m_Type == RichText) {
292         pValue = FPDF_GetFieldAttr(m_pDict, "V");
293       }
294       if (!pValue && m_Type != Text) {
295         pValue = FPDF_GetFieldAttr(m_pDict, "DV");
296       }
297     }
298     if (!pValue) {
299       return CFX_WideString();
300     }
301   }
302   switch (pValue->GetType()) {
303     case PDFOBJ_STRING:
304     case PDFOBJ_STREAM:
305       return pValue->GetUnicodeText();
306     case PDFOBJ_ARRAY:
307       pValue = pValue->AsArray()->GetElementValue(0);
308       if (pValue)
309         return pValue->GetUnicodeText();
310       break;
311   }
312   return CFX_WideString();
313 }
GetValue()314 CFX_WideString CPDF_FormField::GetValue() {
315   return GetValue(FALSE);
316 }
GetDefaultValue()317 CFX_WideString CPDF_FormField::GetDefaultValue() {
318   return GetValue(TRUE);
319 }
SetValue(const CFX_WideString & value,FX_BOOL bDefault,FX_BOOL bNotify)320 FX_BOOL CPDF_FormField::SetValue(const CFX_WideString& value,
321                                  FX_BOOL bDefault,
322                                  FX_BOOL bNotify) {
323   switch (m_Type) {
324     case CheckBox:
325     case RadioButton: {
326       SetCheckValue(value, bDefault, bNotify);
327       return TRUE;
328     }
329     case File:
330     case RichText:
331     case Text:
332     case ComboBox: {
333       CFX_WideString csValue = value;
334       if (bNotify && m_pForm->m_pFormNotify) {
335         int iRet = m_pForm->m_pFormNotify->BeforeValueChange(this, csValue);
336         if (iRet < 0) {
337           return FALSE;
338         }
339       }
340       int iIndex = FindOptionValue(csValue);
341       if (iIndex < 0) {
342         CFX_ByteString bsEncodeText = PDF_EncodeText(csValue);
343         m_pDict->SetAtString(bDefault ? "DV" : "V", bsEncodeText);
344         if (m_Type == RichText && !bDefault) {
345           m_pDict->SetAtString("RV", bsEncodeText);
346         }
347         m_pDict->RemoveAt("I");
348       } else {
349         m_pDict->SetAtString(bDefault ? "DV" : "V", PDF_EncodeText(csValue));
350         if (bDefault) {
351         } else {
352           ClearSelection();
353           SetItemSelection(iIndex, TRUE);
354         }
355       }
356       if (bNotify && m_pForm->m_pFormNotify) {
357         m_pForm->m_pFormNotify->AfterValueChange(this);
358       }
359       m_pForm->m_bUpdated = TRUE;
360     } break;
361     case ListBox: {
362       int iIndex = FindOptionValue(value);
363       if (iIndex < 0) {
364         return FALSE;
365       }
366       if (bDefault && iIndex == GetDefaultSelectedItem()) {
367         return FALSE;
368       }
369       if (bNotify && m_pForm->m_pFormNotify) {
370         CFX_WideString csValue = value;
371         int iRet = m_pForm->m_pFormNotify->BeforeSelectionChange(this, csValue);
372         if (iRet < 0) {
373           return FALSE;
374         }
375       }
376       if (bDefault) {
377       } else {
378         ClearSelection();
379         SetItemSelection(iIndex, TRUE);
380       }
381       if (bNotify && m_pForm->m_pFormNotify) {
382         m_pForm->m_pFormNotify->AfterSelectionChange(this);
383       }
384       m_pForm->m_bUpdated = TRUE;
385       break;
386     }
387     default:
388       break;
389   }
390   if (CPDF_InterForm::m_bUpdateAP) {
391     UpdateAP(NULL);
392   }
393   return TRUE;
394 }
SetValue(const CFX_WideString & value,FX_BOOL bNotify)395 FX_BOOL CPDF_FormField::SetValue(const CFX_WideString& value, FX_BOOL bNotify) {
396   return SetValue(value, FALSE, bNotify);
397 }
GetMaxLen()398 int CPDF_FormField::GetMaxLen() {
399   if (CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict, "MaxLen"))
400     return pObj->GetInteger();
401 
402   for (int i = 0; i < m_ControlList.GetSize(); i++) {
403     CPDF_FormControl* pControl = m_ControlList.GetAt(i);
404     if (!pControl)
405       continue;
406 
407     CPDF_Dictionary* pWidgetDict = pControl->m_pWidgetDict;
408     if (pWidgetDict->KeyExist("MaxLen"))
409       return pWidgetDict->GetInteger("MaxLen");
410   }
411   return 0;
412 }
CountSelectedItems()413 int CPDF_FormField::CountSelectedItems() {
414   CPDF_Object* pValue = FPDF_GetFieldAttr(m_pDict, "V");
415   if (!pValue) {
416     pValue = FPDF_GetFieldAttr(m_pDict, "I");
417     if (!pValue)
418       return 0;
419   }
420 
421   if (pValue->IsString() || pValue->IsNumber())
422     return pValue->GetString().IsEmpty() ? 0 : 1;
423   if (CPDF_Array* pArray = pValue->AsArray())
424     return pArray->GetCount();
425   return 0;
426 }
GetSelectedIndex(int index)427 int CPDF_FormField::GetSelectedIndex(int index) {
428   CPDF_Object* pValue = FPDF_GetFieldAttr(m_pDict, "V");
429   if (!pValue) {
430     pValue = FPDF_GetFieldAttr(m_pDict, "I");
431     if (!pValue)
432       return -1;
433   }
434   if (pValue->IsNumber())
435     return pValue->GetInteger();
436 
437   CFX_WideString sel_value;
438   if (pValue->IsString()) {
439     if (index != 0)
440       return -1;
441     sel_value = pValue->GetUnicodeText();
442   } else {
443     CPDF_Array* pArray = pValue->AsArray();
444     if (!pArray || index < 0)
445       return -1;
446 
447     CPDF_Object* elementValue = pArray->GetElementValue(index);
448     sel_value =
449         elementValue ? elementValue->GetUnicodeText() : CFX_WideString();
450   }
451   if (index < CountSelectedOptions()) {
452     int iOptIndex = GetSelectedOptionIndex(index);
453     CFX_WideString csOpt = GetOptionValue(iOptIndex);
454     if (csOpt == sel_value) {
455       return iOptIndex;
456     }
457   }
458   int nOpts = CountOptions();
459   for (int i = 0; i < nOpts; i++) {
460     if (sel_value == GetOptionValue(i)) {
461       return i;
462     }
463   }
464   return -1;
465 }
ClearSelection(FX_BOOL bNotify)466 FX_BOOL CPDF_FormField::ClearSelection(FX_BOOL bNotify) {
467   if (bNotify && m_pForm->m_pFormNotify) {
468     int iRet = 0;
469     CFX_WideString csValue;
470     int iIndex = GetSelectedIndex(0);
471     if (iIndex >= 0) {
472       csValue = GetOptionLabel(iIndex);
473     }
474     if (GetType() == ListBox) {
475       iRet = m_pForm->m_pFormNotify->BeforeSelectionChange(this, csValue);
476     }
477     if (GetType() == ComboBox) {
478       iRet = m_pForm->m_pFormNotify->BeforeValueChange(this, csValue);
479     }
480     if (iRet < 0) {
481       return FALSE;
482     }
483   }
484   m_pDict->RemoveAt("V");
485   m_pDict->RemoveAt("I");
486   if (bNotify && m_pForm->m_pFormNotify) {
487     if (GetType() == ListBox) {
488       m_pForm->m_pFormNotify->AfterSelectionChange(this);
489     }
490     if (GetType() == ComboBox) {
491       m_pForm->m_pFormNotify->AfterValueChange(this);
492     }
493   }
494   if (CPDF_InterForm::m_bUpdateAP) {
495     UpdateAP(NULL);
496   }
497   m_pForm->m_bUpdated = TRUE;
498   return TRUE;
499 }
IsItemSelected(int index)500 FX_BOOL CPDF_FormField::IsItemSelected(int index) {
501   ASSERT(GetType() == ComboBox || GetType() == ListBox);
502   if (index < 0 || index >= CountOptions()) {
503     return FALSE;
504   }
505   if (IsOptionSelected(index)) {
506     return TRUE;
507   }
508   CFX_WideString opt_value = GetOptionValue(index);
509   CPDF_Object* pValue = FPDF_GetFieldAttr(m_pDict, "V");
510   if (!pValue) {
511     pValue = FPDF_GetFieldAttr(m_pDict, "I");
512     if (!pValue) {
513       return FALSE;
514     }
515   }
516 
517   if (pValue->IsString())
518     return pValue->GetUnicodeText() == opt_value;
519 
520   if (pValue->IsNumber()) {
521     if (pValue->GetString().IsEmpty())
522       return FALSE;
523     return (pValue->GetInteger() == index);
524   }
525 
526   CPDF_Array* pArray = pValue->AsArray();
527   if (!pArray)
528     return FALSE;
529 
530   int iPos = -1;
531   for (int j = 0; j < CountSelectedOptions(); j++) {
532     if (GetSelectedOptionIndex(j) == index) {
533       iPos = j;
534       break;
535     }
536   }
537   for (FX_DWORD i = 0; i < pArray->GetCount(); i++)
538     if (pArray->GetElementValue(i)->GetUnicodeText() == opt_value &&
539         (int)i == iPos) {
540       return TRUE;
541     }
542   return FALSE;
543 }
SetItemSelection(int index,FX_BOOL bSelected,FX_BOOL bNotify)544 FX_BOOL CPDF_FormField::SetItemSelection(int index,
545                                          FX_BOOL bSelected,
546                                          FX_BOOL bNotify) {
547   ASSERT(GetType() == ComboBox || GetType() == ListBox);
548   if (index < 0 || index >= CountOptions()) {
549     return FALSE;
550   }
551   CFX_WideString opt_value = GetOptionValue(index);
552   if (bNotify && m_pForm->m_pFormNotify) {
553     int iRet = 0;
554     if (GetType() == ListBox) {
555       iRet = m_pForm->m_pFormNotify->BeforeSelectionChange(this, opt_value);
556     }
557     if (GetType() == ComboBox) {
558       iRet = m_pForm->m_pFormNotify->BeforeValueChange(this, opt_value);
559     }
560     if (iRet < 0) {
561       return FALSE;
562     }
563   }
564   if (!bSelected) {
565     CPDF_Object* pValue = FPDF_GetFieldAttr(m_pDict, "V");
566     if (pValue) {
567       if (m_Type == ListBox) {
568         SelectOption(index, FALSE);
569         if (pValue->IsString()) {
570           if (pValue->GetUnicodeText() == opt_value) {
571             m_pDict->RemoveAt("V");
572           }
573         } else if (pValue->IsArray()) {
574           CPDF_Array* pArray = new CPDF_Array;
575           int iCount = CountOptions();
576           for (int i = 0; i < iCount; i++) {
577             if (i != index) {
578               if (IsItemSelected(i)) {
579                 opt_value = GetOptionValue(i);
580                 pArray->AddString(PDF_EncodeText(opt_value));
581               }
582             }
583           }
584           if (pArray->GetCount() < 1) {
585             pArray->Release();
586           } else {
587             m_pDict->SetAt("V", pArray);
588           }
589         }
590       } else if (m_Type == ComboBox) {
591         m_pDict->RemoveAt("V");
592         m_pDict->RemoveAt("I");
593       }
594     }
595   } else {
596     if (m_Type == ListBox) {
597       SelectOption(index, TRUE);
598       if (!(m_Flags & FORMLIST_MULTISELECT)) {
599         m_pDict->SetAtString("V", PDF_EncodeText(opt_value));
600       } else {
601         CPDF_Array* pArray = new CPDF_Array;
602         int iCount = CountOptions();
603         for (int i = 0; i < iCount; i++) {
604           FX_BOOL bSelected;
605           if (i != index) {
606             bSelected = IsItemSelected(i);
607           } else {
608             bSelected = TRUE;
609           }
610           if (bSelected) {
611             opt_value = GetOptionValue(i);
612             pArray->AddString(PDF_EncodeText(opt_value));
613           }
614         }
615         m_pDict->SetAt("V", pArray);
616       }
617     } else if (m_Type == ComboBox) {
618       m_pDict->SetAtString("V", PDF_EncodeText(opt_value));
619       CPDF_Array* pI = new CPDF_Array;
620       pI->AddInteger(index);
621       m_pDict->SetAt("I", pI);
622     }
623   }
624   if (bNotify && m_pForm->m_pFormNotify) {
625     if (GetType() == ListBox) {
626       m_pForm->m_pFormNotify->AfterSelectionChange(this);
627     }
628     if (GetType() == ComboBox) {
629       m_pForm->m_pFormNotify->AfterValueChange(this);
630     }
631   }
632   if (CPDF_InterForm::m_bUpdateAP) {
633     UpdateAP(NULL);
634   }
635   m_pForm->m_bUpdated = TRUE;
636   return TRUE;
637 }
IsItemDefaultSelected(int index)638 FX_BOOL CPDF_FormField::IsItemDefaultSelected(int index) {
639   ASSERT(GetType() == ComboBox || GetType() == ListBox);
640   if (index < 0 || index >= CountOptions()) {
641     return FALSE;
642   }
643   int iDVIndex = GetDefaultSelectedItem();
644   if (iDVIndex < 0) {
645     return FALSE;
646   }
647   return (iDVIndex == index);
648 }
GetDefaultSelectedItem()649 int CPDF_FormField::GetDefaultSelectedItem() {
650   ASSERT(GetType() == ComboBox || GetType() == ListBox);
651   CPDF_Object* pValue = FPDF_GetFieldAttr(m_pDict, "DV");
652   if (!pValue) {
653     return -1;
654   }
655   CFX_WideString csDV = pValue->GetUnicodeText();
656   if (csDV.IsEmpty()) {
657     return -1;
658   }
659   int iCount = CountOptions();
660   for (int i = 0; i < iCount; i++) {
661     if (csDV == GetOptionValue(i)) {
662       return i;
663     }
664   }
665   return -1;
666 }
UpdateAP(CPDF_FormControl * pControl)667 void CPDF_FormField::UpdateAP(CPDF_FormControl* pControl) {
668   if (m_Type == PushButton) {
669     return;
670   }
671   if (m_Type == RadioButton || m_Type == CheckBox) {
672     return;
673   }
674   if (!m_pForm->m_bGenerateAP) {
675     return;
676   }
677   for (int i = 0; i < CountControls(); i++) {
678     CPDF_FormControl* pControl = GetControl(i);
679     FPDF_GenerateAP(m_pForm->m_pDocument, pControl->m_pWidgetDict);
680   }
681 }
CountOptions()682 int CPDF_FormField::CountOptions() {
683   CPDF_Array* pArray = ToArray(FPDF_GetFieldAttr(m_pDict, "Opt"));
684   return pArray ? pArray->GetCount() : 0;
685 }
GetOptionText(int index,int sub_index)686 CFX_WideString CPDF_FormField::GetOptionText(int index, int sub_index) {
687   CPDF_Array* pArray = ToArray(FPDF_GetFieldAttr(m_pDict, "Opt"));
688   if (!pArray)
689     return CFX_WideString();
690 
691   CPDF_Object* pOption = pArray->GetElementValue(index);
692   if (!pOption)
693     return CFX_WideString();
694   if (CPDF_Array* pOptionArray = pOption->AsArray())
695     pOption = pOptionArray->GetElementValue(sub_index);
696 
697   CPDF_String* pString = ToString(pOption);
698   return pString ? pString->GetUnicodeText() : CFX_WideString();
699 }
GetOptionLabel(int index)700 CFX_WideString CPDF_FormField::GetOptionLabel(int index) {
701   return GetOptionText(index, 1);
702 }
GetOptionValue(int index)703 CFX_WideString CPDF_FormField::GetOptionValue(int index) {
704   return GetOptionText(index, 0);
705 }
FindOption(CFX_WideString csOptLabel)706 int CPDF_FormField::FindOption(CFX_WideString csOptLabel) {
707   int iCount = CountOptions();
708   for (int i = 0; i < iCount; i++) {
709     CFX_WideString csValue = GetOptionValue(i);
710     if (csValue == csOptLabel) {
711       return i;
712     }
713   }
714   return -1;
715 }
FindOptionValue(const CFX_WideString & csOptValue,int iStartIndex)716 int CPDF_FormField::FindOptionValue(const CFX_WideString& csOptValue,
717                                     int iStartIndex) {
718   if (iStartIndex < 0) {
719     iStartIndex = 0;
720   }
721   int iCount = CountOptions();
722   for (; iStartIndex < iCount; iStartIndex++) {
723     CFX_WideString csValue = GetOptionValue(iStartIndex);
724     if (csValue == csOptValue) {
725       return iStartIndex;
726     }
727   }
728   return -1;
729 }
730 #ifdef PDF_ENABLE_XFA
InsertOption(CFX_WideString csOptLabel,int index,FX_BOOL bNotify)731 int CPDF_FormField::InsertOption(CFX_WideString csOptLabel,
732                                  int index,
733                                  FX_BOOL bNotify) {
734   if (csOptLabel.IsEmpty())
735     return -1;
736 
737   if (bNotify && m_pForm->m_pFormNotify) {
738     int iRet = 0;
739     if (GetType() == ListBox)
740       iRet = m_pForm->m_pFormNotify->BeforeSelectionChange(this, csOptLabel);
741     if (GetType() == ComboBox)
742       iRet = m_pForm->m_pFormNotify->BeforeValueChange(this, csOptLabel);
743     if (iRet < 0)
744       return -1;
745   }
746 
747   CFX_ByteString csStr = PDF_EncodeText(csOptLabel, csOptLabel.GetLength());
748   CPDF_Object* pValue = FPDF_GetFieldAttr(m_pDict, "Opt");
749   CPDF_Array* pOpt = ToArray(pValue);
750   if (!pOpt) {
751     pOpt = new CPDF_Array;
752     m_pDict->SetAt("Opt", pOpt);
753   }
754 
755   int iCount = (int)pOpt->GetCount();
756   if (index < 0 || index >= iCount) {
757     pOpt->AddString(csStr);
758     index = iCount;
759   } else {
760     CPDF_String* pString = new CPDF_String(csStr, FALSE);
761     pOpt->InsertAt(index, pString);
762   }
763 
764   if (bNotify && m_pForm->m_pFormNotify) {
765     if (GetType() == ListBox)
766       m_pForm->m_pFormNotify->AfterSelectionChange(this);
767     if (GetType() == ComboBox)
768       m_pForm->m_pFormNotify->AfterValueChange(this);
769   }
770   m_pForm->m_bUpdated = TRUE;
771   return index;
772 }
ClearOptions(FX_BOOL bNotify)773 FX_BOOL CPDF_FormField::ClearOptions(FX_BOOL bNotify) {
774   if (bNotify && m_pForm->m_pFormNotify) {
775     int iRet = 0;
776     CFX_WideString csValue;
777     int iIndex = GetSelectedIndex(0);
778     if (iIndex >= 0)
779       csValue = GetOptionLabel(iIndex);
780     if (GetType() == ListBox)
781       iRet = m_pForm->m_pFormNotify->BeforeSelectionChange(this, csValue);
782     if (GetType() == ComboBox)
783       iRet = m_pForm->m_pFormNotify->BeforeValueChange(this, csValue);
784     if (iRet < 0)
785       return FALSE;
786   }
787 
788   m_pDict->RemoveAt("Opt");
789   m_pDict->RemoveAt("V");
790   m_pDict->RemoveAt("DV");
791   m_pDict->RemoveAt("I");
792   m_pDict->RemoveAt("TI");
793 
794   if (bNotify && m_pForm->m_pFormNotify) {
795     if (GetType() == ListBox)
796       m_pForm->m_pFormNotify->AfterSelectionChange(this);
797     if (GetType() == ComboBox)
798       m_pForm->m_pFormNotify->AfterValueChange(this);
799   }
800 
801   m_pForm->m_bUpdated = TRUE;
802   return TRUE;
803 }
804 #endif  // PDF_ENABLE_XFA
CheckControl(int iControlIndex,FX_BOOL bChecked,FX_BOOL bNotify)805 FX_BOOL CPDF_FormField::CheckControl(int iControlIndex,
806                                      FX_BOOL bChecked,
807                                      FX_BOOL bNotify) {
808   ASSERT(GetType() == CheckBox || GetType() == RadioButton);
809   CPDF_FormControl* pControl = GetControl(iControlIndex);
810   if (!pControl) {
811     return FALSE;
812   }
813   if (!bChecked && pControl->IsChecked() == bChecked) {
814     return FALSE;
815   }
816   CFX_ByteArray statusArray;
817   if (bNotify && m_pForm->m_pFormNotify) {
818     SaveCheckedFieldStatus(this, statusArray);
819   }
820   CFX_WideString csWExport = pControl->GetExportValue();
821   CFX_ByteString csBExport = PDF_EncodeText(csWExport);
822   int iCount = CountControls();
823   FX_BOOL bUnison = PDF_FormField_IsUnison(this);
824   for (int i = 0; i < iCount; i++) {
825     CPDF_FormControl* pCtrl = GetControl(i);
826     if (bUnison) {
827       CFX_WideString csEValue = pCtrl->GetExportValue();
828       if (csEValue == csWExport) {
829         if (pCtrl->GetOnStateName() == pControl->GetOnStateName()) {
830           pCtrl->CheckControl(bChecked);
831         } else if (bChecked) {
832           pCtrl->CheckControl(FALSE);
833         }
834       } else if (bChecked) {
835         pCtrl->CheckControl(FALSE);
836       }
837     } else {
838       if (i == iControlIndex) {
839         pCtrl->CheckControl(bChecked);
840       } else if (bChecked) {
841         pCtrl->CheckControl(FALSE);
842       }
843     }
844   }
845   CPDF_Object* pOpt = FPDF_GetFieldAttr(m_pDict, "Opt");
846   if (!ToArray(pOpt)) {
847     if (bChecked) {
848       m_pDict->SetAtName("V", csBExport);
849     } else {
850       CFX_ByteString csV;
851       CPDF_Object* pV = FPDF_GetFieldAttr(m_pDict, "V");
852       if (pV) {
853         csV = pV->GetString();
854       }
855       if (csV == csBExport) {
856         m_pDict->SetAtName("V", "Off");
857       }
858     }
859   } else if (bChecked) {
860     CFX_ByteString csIndex;
861     csIndex.Format("%d", iControlIndex);
862     m_pDict->SetAtName("V", csIndex);
863   }
864   if (bNotify && m_pForm->m_pFormNotify) {
865     m_pForm->m_pFormNotify->AfterCheckedStatusChange(this, statusArray);
866   }
867   m_pForm->m_bUpdated = TRUE;
868   return TRUE;
869 }
GetCheckValue(FX_BOOL bDefault)870 CFX_WideString CPDF_FormField::GetCheckValue(FX_BOOL bDefault) {
871   ASSERT(GetType() == CheckBox || GetType() == RadioButton);
872   CFX_WideString csExport = L"Off";
873   FX_BOOL bChecked;
874   int iCount = CountControls();
875   for (int i = 0; i < iCount; i++) {
876     CPDF_FormControl* pControl = GetControl(i);
877     if (bDefault) {
878       bChecked = pControl->IsDefaultChecked();
879     } else {
880       bChecked = pControl->IsChecked();
881     }
882     if (bChecked) {
883       csExport = pControl->GetExportValue();
884       break;
885     }
886   }
887   return csExport;
888 }
SetCheckValue(const CFX_WideString & value,FX_BOOL bDefault,FX_BOOL bNotify)889 FX_BOOL CPDF_FormField::SetCheckValue(const CFX_WideString& value,
890                                       FX_BOOL bDefault,
891                                       FX_BOOL bNotify) {
892   ASSERT(GetType() == CheckBox || GetType() == RadioButton);
893   CFX_ByteArray statusArray;
894   if (bNotify && m_pForm->m_pFormNotify) {
895     SaveCheckedFieldStatus(this, statusArray);
896   }
897   int iCount = CountControls();
898   for (int i = 0; i < iCount; i++) {
899     CPDF_FormControl* pControl = GetControl(i);
900     CFX_WideString csExport = pControl->GetExportValue();
901     if (csExport == value) {
902       if (bDefault) {
903       } else {
904         CheckControl(GetControlIndex(pControl), TRUE);
905       }
906       break;
907     } else {
908       if (bDefault) {
909       } else {
910         CheckControl(GetControlIndex(pControl), FALSE);
911       }
912     }
913   }
914   if (bNotify && m_pForm->m_pFormNotify) {
915     m_pForm->m_pFormNotify->AfterCheckedStatusChange(this, statusArray);
916   }
917   m_pForm->m_bUpdated = TRUE;
918   return TRUE;
919 }
GetTopVisibleIndex()920 int CPDF_FormField::GetTopVisibleIndex() {
921   CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict, "TI");
922   if (!pObj) {
923     return 0;
924   }
925   return pObj->GetInteger();
926 }
CountSelectedOptions()927 int CPDF_FormField::CountSelectedOptions() {
928   CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict, "I");
929   if (!pObj) {
930     return 0;
931   }
932   CPDF_Array* pArray = pObj->GetArray();
933   if (!pArray) {
934     return 0;
935   }
936   return (int)pArray->GetCount();
937 }
GetSelectedOptionIndex(int index)938 int CPDF_FormField::GetSelectedOptionIndex(int index) {
939   CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict, "I");
940   if (!pObj) {
941     return -1;
942   }
943   CPDF_Array* pArray = pObj->GetArray();
944   if (!pArray) {
945     return -1;
946   }
947   int iCount = (int)pArray->GetCount();
948   if (iCount > 0 && index < iCount) {
949     return pArray->GetInteger(index);
950   }
951   return -1;
952 }
IsOptionSelected(int iOptIndex)953 FX_BOOL CPDF_FormField::IsOptionSelected(int iOptIndex) {
954   CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict, "I");
955   if (!pObj) {
956     return FALSE;
957   }
958   CPDF_Array* pArray = pObj->GetArray();
959   if (!pArray) {
960     return FALSE;
961   }
962   int iCount = (int)pArray->GetCount();
963   for (int i = 0; i < iCount; i++) {
964     if (pArray->GetInteger(i) == iOptIndex) {
965       return TRUE;
966     }
967   }
968   return FALSE;
969 }
SelectOption(int iOptIndex,FX_BOOL bSelected,FX_BOOL bNotify)970 FX_BOOL CPDF_FormField::SelectOption(int iOptIndex,
971                                      FX_BOOL bSelected,
972                                      FX_BOOL bNotify) {
973   CPDF_Array* pArray = m_pDict->GetArray("I");
974   if (!pArray) {
975     if (!bSelected) {
976       return TRUE;
977     }
978     pArray = new CPDF_Array;
979     m_pDict->SetAt("I", pArray);
980   }
981   FX_BOOL bReturn = FALSE;
982   for (int i = 0; i < (int)pArray->GetCount(); i++) {
983     int iFind = pArray->GetInteger(i);
984     if (iFind == iOptIndex) {
985       if (bSelected) {
986         return TRUE;
987       }
988       if (bNotify && m_pForm->m_pFormNotify) {
989         int iRet = 0;
990         CFX_WideString csValue = GetOptionLabel(iOptIndex);
991         if (GetType() == ListBox) {
992           iRet = m_pForm->m_pFormNotify->BeforeSelectionChange(this, csValue);
993         }
994         if (GetType() == ComboBox) {
995           iRet = m_pForm->m_pFormNotify->BeforeValueChange(this, csValue);
996         }
997         if (iRet < 0) {
998           return FALSE;
999         }
1000       }
1001       pArray->RemoveAt(i);
1002       bReturn = TRUE;
1003       break;
1004     } else if (iFind > iOptIndex) {
1005       if (!bSelected) {
1006         continue;
1007       }
1008       if (bNotify && m_pForm->m_pFormNotify) {
1009         int iRet = 0;
1010         CFX_WideString csValue = GetOptionLabel(iOptIndex);
1011         if (GetType() == ListBox) {
1012           iRet = m_pForm->m_pFormNotify->BeforeSelectionChange(this, csValue);
1013         }
1014         if (GetType() == ComboBox) {
1015           iRet = m_pForm->m_pFormNotify->BeforeValueChange(this, csValue);
1016         }
1017         if (iRet < 0) {
1018           return FALSE;
1019         }
1020       }
1021       CPDF_Number* pNum = new CPDF_Number(iOptIndex);
1022       pArray->InsertAt(i, pNum);
1023       bReturn = TRUE;
1024       break;
1025     }
1026   }
1027   if (!bReturn) {
1028     if (bSelected) {
1029       pArray->AddInteger(iOptIndex);
1030     }
1031     if (pArray->GetCount() == 0) {
1032       m_pDict->RemoveAt("I");
1033     }
1034   }
1035   if (bNotify && m_pForm->m_pFormNotify) {
1036     if (GetType() == ListBox) {
1037       m_pForm->m_pFormNotify->AfterSelectionChange(this);
1038     }
1039     if (GetType() == ComboBox) {
1040       m_pForm->m_pFormNotify->AfterValueChange(this);
1041     }
1042   }
1043   m_pForm->m_bUpdated = TRUE;
1044   return TRUE;
1045 }
ClearSelectedOptions(FX_BOOL bNotify)1046 FX_BOOL CPDF_FormField::ClearSelectedOptions(FX_BOOL bNotify) {
1047   if (bNotify && m_pForm->m_pFormNotify) {
1048     int iRet = 0;
1049     CFX_WideString csValue;
1050     int iIndex = GetSelectedIndex(0);
1051     if (iIndex >= 0) {
1052       csValue = GetOptionLabel(iIndex);
1053     }
1054     if (GetType() == ListBox) {
1055       iRet = m_pForm->m_pFormNotify->BeforeSelectionChange(this, csValue);
1056     }
1057     if (GetType() == ComboBox) {
1058       iRet = m_pForm->m_pFormNotify->BeforeValueChange(this, csValue);
1059     }
1060     if (iRet < 0) {
1061       return FALSE;
1062     }
1063   }
1064   m_pDict->RemoveAt("I");
1065   if (bNotify && m_pForm->m_pFormNotify) {
1066     if (GetType() == ListBox) {
1067       m_pForm->m_pFormNotify->AfterSelectionChange(this);
1068     }
1069     if (GetType() == ComboBox) {
1070       m_pForm->m_pFormNotify->AfterValueChange(this);
1071     }
1072   }
1073   m_pForm->m_bUpdated = TRUE;
1074   return TRUE;
1075 }
LoadDA()1076 void CPDF_FormField::LoadDA() {
1077   CFX_ByteString DA;
1078   if (CPDF_Object* pObj_t = FPDF_GetFieldAttr(m_pDict, "DA")) {
1079     DA = pObj_t->GetString();
1080   }
1081   if (DA.IsEmpty() && m_pForm->m_pFormDict) {
1082     DA = m_pForm->m_pFormDict->GetString("DA");
1083   }
1084   if (DA.IsEmpty()) {
1085     return;
1086   }
1087   CPDF_SimpleParser syntax(DA);
1088   syntax.FindTagParam("Tf", 2);
1089   CFX_ByteString font_name = syntax.GetWord();
1090   CPDF_Dictionary* pFontDict = NULL;
1091   if (m_pForm->m_pFormDict && m_pForm->m_pFormDict->GetDict("DR") &&
1092       m_pForm->m_pFormDict->GetDict("DR")->GetDict("Font"))
1093     pFontDict = m_pForm->m_pFormDict->GetDict("DR")->GetDict("Font")->GetDict(
1094         font_name);
1095 
1096   if (!pFontDict) {
1097     return;
1098   }
1099   m_pFont = m_pForm->m_pDocument->LoadFont(pFontDict);
1100   m_FontSize = FX_atof(syntax.GetWord());
1101 }
1102