Clean up CPDF_AnnotList.
[pdfium.git] / core / src / fpdfdoc / doc_formfield.cpp
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 "../../include/fpdfdoc/fpdf_doc.h"
8 #include "doc_utils.h"
9
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 }
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 }
28 CPDF_FormField::~CPDF_FormField() {}
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 }
98 CFX_WideString CPDF_FormField::GetFullName() {
99   return ::GetFullName(m_pDict);
100 }
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 != NULL) {
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 != NULL) {
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 != NULL) {
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 != NULL) {
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 != NULL) {
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 != NULL) {
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 != NULL) {
170         csDValue = pDV->GetUnicodeText();
171       }
172       CPDF_Object* pV = FPDF_GetFieldAttr(m_pDict, "V");
173       CFX_WideString csValue;
174       if (pV != NULL) {
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 != NULL) {
182         int iRet = m_pForm->m_pFormNotify->BeforeValueChange(this, csDValue);
183         if (iRet < 0) {
184           return FALSE;
185         }
186       }
187       if (pDV == NULL) {
188         m_pDict->RemoveAt("V");
189         m_pDict->RemoveAt("RV");
190       } else {
191         CPDF_Object* pClone = pDV->Clone();
192         if (pClone == NULL) {
193           return FALSE;
194         }
195         m_pDict->SetAt("V", pClone);
196         if (pRV) {
197           CPDF_Object* pCloneR = pDV->Clone();
198           m_pDict->SetAt("RV", pCloneR);
199         }
200       }
201       if (bNotify && m_pForm->m_pFormNotify != NULL) {
202         m_pForm->m_pFormNotify->AfterValueChange(this);
203       }
204       m_pForm->m_bUpdated = TRUE;
205     } break;
206   }
207   return TRUE;
208 }
209 int CPDF_FormField::GetControlIndex(const CPDF_FormControl* pControl) {
210   if (pControl == NULL) {
211     return -1;
212   }
213   int iCount = m_ControlList.GetSize();
214   for (int i = 0; i < iCount; i++) {
215     CPDF_FormControl* pFind = (CPDF_FormControl*)m_ControlList.GetAt(i);
216     if (pFind == pControl) {
217       return i;
218     }
219   }
220   return -1;
221 }
222 int CPDF_FormField::GetFieldType() {
223   switch (m_Type) {
224     case PushButton:
225       return FIELDTYPE_PUSHBUTTON;
226     case CheckBox:
227       return FIELDTYPE_CHECKBOX;
228     case RadioButton:
229       return FIELDTYPE_RADIOBUTTON;
230     case ComboBox:
231       return FIELDTYPE_COMBOBOX;
232     case ListBox:
233       return FIELDTYPE_LISTBOX;
234     case Text:
235     case RichText:
236     case File:
237       return FIELDTYPE_TEXTFIELD;
238     case Sign:
239       return FIELDTYPE_SIGNATURE;
240     default:
241       break;
242   }
243   return FIELDTYPE_UNKNOWN;
244 }
245 CPDF_AAction CPDF_FormField::GetAdditionalAction() {
246   CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict, "AA");
247   if (pObj == NULL) {
248     return NULL;
249   }
250   return pObj->GetDict();
251 }
252 CFX_WideString CPDF_FormField::GetAlternateName() {
253   CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict, "TU");
254   if (pObj == NULL) {
255     return L"";
256   }
257   return pObj->GetUnicodeText();
258 }
259 CFX_WideString CPDF_FormField::GetMappingName() {
260   CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict, "TM");
261   if (pObj == NULL) {
262     return L"";
263   }
264   return pObj->GetUnicodeText();
265 }
266 FX_DWORD CPDF_FormField::GetFieldFlags() {
267   CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict, "Ff");
268   if (pObj == NULL) {
269     return 0;
270   }
271   return pObj->GetInteger();
272 }
273 CFX_ByteString CPDF_FormField::GetDefaultStyle() {
274   CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict, "DS");
275   if (pObj == NULL) {
276     return "";
277   }
278   return pObj->GetString();
279 }
280 CFX_WideString CPDF_FormField::GetRichTextString() {
281   CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict, "RV");
282   if (pObj == NULL) {
283     return L"";
284   }
285   return pObj->GetUnicodeText();
286 }
287 CFX_WideString CPDF_FormField::GetValue(FX_BOOL bDefault) {
288   if (GetType() == CheckBox || GetType() == RadioButton) {
289     return GetCheckValue(bDefault);
290   }
291   CPDF_Object* pValue = FPDF_GetFieldAttr(m_pDict, bDefault ? "DV" : "V");
292   if (pValue == NULL) {
293     if (!bDefault) {
294       if (m_Type == RichText) {
295         pValue = FPDF_GetFieldAttr(m_pDict, "V");
296       }
297       if (pValue == NULL && m_Type != Text) {
298         pValue = FPDF_GetFieldAttr(m_pDict, "DV");
299       }
300     }
301     if (pValue == NULL) {
302       return CFX_WideString();
303     }
304   }
305   switch (pValue->GetType()) {
306     case PDFOBJ_STRING:
307     case PDFOBJ_STREAM:
308       return pValue->GetUnicodeText();
309     case PDFOBJ_ARRAY:
310       pValue = pValue->AsArray()->GetElementValue(0);
311       if (pValue)
312         return pValue->GetUnicodeText();
313       break;
314   }
315   return CFX_WideString();
316 }
317 CFX_WideString CPDF_FormField::GetValue() {
318   return GetValue(FALSE);
319 }
320 CFX_WideString CPDF_FormField::GetDefaultValue() {
321   return GetValue(TRUE);
322 }
323 FX_BOOL CPDF_FormField::SetValue(const CFX_WideString& value,
324                                  FX_BOOL bDefault,
325                                  FX_BOOL bNotify) {
326   switch (m_Type) {
327     case CheckBox:
328     case RadioButton: {
329       SetCheckValue(value, bDefault, bNotify);
330       return TRUE;
331     }
332     case File:
333     case RichText:
334     case Text:
335     case ComboBox: {
336       CFX_WideString csValue = value;
337       if (bNotify && m_pForm->m_pFormNotify != NULL) {
338         int iRet = m_pForm->m_pFormNotify->BeforeValueChange(this, csValue);
339         if (iRet < 0) {
340           return FALSE;
341         }
342       }
343       int iIndex = FindOptionValue(csValue);
344       if (iIndex < 0) {
345         CFX_ByteString bsEncodeText = PDF_EncodeText(csValue);
346         m_pDict->SetAtString(bDefault ? "DV" : "V", bsEncodeText);
347         if (m_Type == RichText && !bDefault) {
348           m_pDict->SetAtString("RV", bsEncodeText);
349         }
350         m_pDict->RemoveAt("I");
351       } else {
352         m_pDict->SetAtString(bDefault ? "DV" : "V", PDF_EncodeText(csValue));
353         if (bDefault) {
354         } else {
355           ClearSelection();
356           SetItemSelection(iIndex, TRUE);
357         }
358       }
359       if (bNotify && m_pForm->m_pFormNotify != NULL) {
360         m_pForm->m_pFormNotify->AfterValueChange(this);
361       }
362       m_pForm->m_bUpdated = TRUE;
363     } break;
364     case ListBox: {
365       int iIndex = FindOptionValue(value);
366       if (iIndex < 0) {
367         return FALSE;
368       }
369       if (bDefault && iIndex == GetDefaultSelectedItem()) {
370         return FALSE;
371       }
372       if (bNotify && m_pForm->m_pFormNotify != NULL) {
373         CFX_WideString csValue = value;
374         int iRet = m_pForm->m_pFormNotify->BeforeSelectionChange(this, csValue);
375         if (iRet < 0) {
376           return FALSE;
377         }
378       }
379       if (bDefault) {
380       } else {
381         ClearSelection();
382         SetItemSelection(iIndex, TRUE);
383       }
384       if (bNotify && m_pForm->m_pFormNotify != NULL) {
385         m_pForm->m_pFormNotify->AfterSelectionChange(this);
386       }
387       m_pForm->m_bUpdated = TRUE;
388       break;
389     }
390     default:
391       break;
392   }
393   if (CPDF_InterForm::m_bUpdateAP) {
394     UpdateAP(NULL);
395   }
396   return TRUE;
397 }
398 FX_BOOL CPDF_FormField::SetValue(const CFX_WideString& value, FX_BOOL bNotify) {
399   return SetValue(value, FALSE, bNotify);
400 }
401 int CPDF_FormField::GetMaxLen() {
402   CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict, "MaxLen");
403   if (pObj == NULL) {
404     int iCount = m_ControlList.GetSize();
405     for (int i = 0; i < iCount; i++) {
406       CPDF_FormControl* pControl = (CPDF_FormControl*)m_ControlList.GetAt(i);
407       if (pControl == NULL) {
408         continue;
409       }
410       CPDF_Dictionary* pWidgetDict = pControl->m_pWidgetDict;
411       if (pWidgetDict->KeyExist("MaxLen")) {
412         return pWidgetDict->GetInteger("MaxLen");
413       }
414     }
415     return 0;
416   }
417   return pObj->GetInteger();
418 }
419 int CPDF_FormField::CountSelectedItems() {
420   CPDF_Object* pValue = FPDF_GetFieldAttr(m_pDict, "V");
421   if (!pValue) {
422     pValue = FPDF_GetFieldAttr(m_pDict, "I");
423     if (!pValue)
424       return 0;
425   }
426
427   if (pValue->IsString() || pValue->IsNumber())
428     return pValue->GetString().IsEmpty() ? 0 : 1;
429   if (CPDF_Array* pArray = pValue->AsArray())
430     return pArray->GetCount();
431   return 0;
432 }
433 int CPDF_FormField::GetSelectedIndex(int index) {
434   CPDF_Object* pValue = FPDF_GetFieldAttr(m_pDict, "V");
435   if (!pValue) {
436     pValue = FPDF_GetFieldAttr(m_pDict, "I");
437     if (!pValue)
438       return -1;
439   }
440   if (pValue->IsNumber())
441     return pValue->GetInteger();
442
443   CFX_WideString sel_value;
444   if (pValue->IsString()) {
445     if (index != 0)
446       return -1;
447     sel_value = pValue->GetUnicodeText();
448   } else {
449     CPDF_Array* pArray = pValue->AsArray();
450     if (!pArray || index < 0)
451       return -1;
452
453     CPDF_Object* elementValue = pArray->GetElementValue(index);
454     sel_value =
455         elementValue ? elementValue->GetUnicodeText() : CFX_WideString();
456   }
457   if (index < CountSelectedOptions()) {
458     int iOptIndex = GetSelectedOptionIndex(index);
459     CFX_WideString csOpt = GetOptionValue(iOptIndex);
460     if (csOpt == sel_value) {
461       return iOptIndex;
462     }
463   }
464   int nOpts = CountOptions();
465   for (int i = 0; i < nOpts; i++) {
466     if (sel_value == GetOptionValue(i)) {
467       return i;
468     }
469   }
470   return -1;
471 }
472 FX_BOOL CPDF_FormField::ClearSelection(FX_BOOL bNotify) {
473   if (bNotify && m_pForm->m_pFormNotify != NULL) {
474     int iRet = 0;
475     CFX_WideString csValue;
476     int iIndex = GetSelectedIndex(0);
477     if (iIndex >= 0) {
478       csValue = GetOptionLabel(iIndex);
479     }
480     if (GetType() == ListBox) {
481       iRet = m_pForm->m_pFormNotify->BeforeSelectionChange(this, csValue);
482     }
483     if (GetType() == ComboBox) {
484       iRet = m_pForm->m_pFormNotify->BeforeValueChange(this, csValue);
485     }
486     if (iRet < 0) {
487       return FALSE;
488     }
489   }
490   m_pDict->RemoveAt("V");
491   m_pDict->RemoveAt("I");
492   if (bNotify && m_pForm->m_pFormNotify != NULL) {
493     if (GetType() == ListBox) {
494       m_pForm->m_pFormNotify->AfterSelectionChange(this);
495     }
496     if (GetType() == ComboBox) {
497       m_pForm->m_pFormNotify->AfterValueChange(this);
498     }
499   }
500   if (CPDF_InterForm::m_bUpdateAP) {
501     UpdateAP(NULL);
502   }
503   m_pForm->m_bUpdated = TRUE;
504   return TRUE;
505 }
506 FX_BOOL CPDF_FormField::IsItemSelected(int index) {
507   ASSERT(GetType() == ComboBox || GetType() == ListBox);
508   if (index < 0 || index >= CountOptions()) {
509     return FALSE;
510   }
511   if (IsOptionSelected(index)) {
512     return TRUE;
513   }
514   CFX_WideString opt_value = GetOptionValue(index);
515   CPDF_Object* pValue = FPDF_GetFieldAttr(m_pDict, "V");
516   if (pValue == NULL) {
517     pValue = FPDF_GetFieldAttr(m_pDict, "I");
518     if (pValue == NULL) {
519       return FALSE;
520     }
521   }
522
523   if (pValue->IsString())
524     return pValue->GetUnicodeText() == opt_value;
525
526   if (pValue->IsNumber()) {
527     if (pValue->GetString().IsEmpty())
528       return FALSE;
529     return (pValue->GetInteger() == index);
530   }
531
532   CPDF_Array* pArray = pValue->AsArray();
533   if (!pArray)
534     return FALSE;
535
536   int iPos = -1;
537   for (int j = 0; j < CountSelectedOptions(); j++) {
538     if (GetSelectedOptionIndex(j) == index) {
539       iPos = j;
540       break;
541     }
542   }
543   for (FX_DWORD i = 0; i < pArray->GetCount(); i++)
544     if (pArray->GetElementValue(i)->GetUnicodeText() == opt_value &&
545         (int)i == iPos) {
546       return TRUE;
547     }
548   return FALSE;
549 }
550 FX_BOOL CPDF_FormField::SetItemSelection(int index,
551                                          FX_BOOL bSelected,
552                                          FX_BOOL bNotify) {
553   ASSERT(GetType() == ComboBox || GetType() == ListBox);
554   if (index < 0 || index >= CountOptions()) {
555     return FALSE;
556   }
557   CFX_WideString opt_value = GetOptionValue(index);
558   if (bNotify && m_pForm->m_pFormNotify != NULL) {
559     int iRet = 0;
560     if (GetType() == ListBox) {
561       iRet = m_pForm->m_pFormNotify->BeforeSelectionChange(this, opt_value);
562     }
563     if (GetType() == ComboBox) {
564       iRet = m_pForm->m_pFormNotify->BeforeValueChange(this, opt_value);
565     }
566     if (iRet < 0) {
567       return FALSE;
568     }
569   }
570   if (!bSelected) {
571     CPDF_Object* pValue = FPDF_GetFieldAttr(m_pDict, "V");
572     if (pValue != NULL) {
573       if (m_Type == ListBox) {
574         SelectOption(index, FALSE);
575         if (pValue->IsString()) {
576           if (pValue->GetUnicodeText() == opt_value) {
577             m_pDict->RemoveAt("V");
578           }
579         } else if (pValue->IsArray()) {
580           CPDF_Array* pArray = CPDF_Array::Create();
581           int iCount = CountOptions();
582           for (int i = 0; i < iCount; i++) {
583             if (i != index) {
584               if (IsItemSelected(i)) {
585                 opt_value = GetOptionValue(i);
586                 pArray->AddString(PDF_EncodeText(opt_value));
587               }
588             }
589           }
590           if (pArray->GetCount() < 1) {
591             pArray->Release();
592           } else {
593             m_pDict->SetAt("V", pArray);
594           }
595         }
596       } else if (m_Type == ComboBox) {
597         m_pDict->RemoveAt("V");
598         m_pDict->RemoveAt("I");
599       }
600     }
601   } else {
602     if (m_Type == ListBox) {
603       SelectOption(index, TRUE);
604       if (!(m_Flags & FORMLIST_MULTISELECT)) {
605         m_pDict->SetAtString("V", PDF_EncodeText(opt_value));
606       } else {
607         CPDF_Array* pArray = CPDF_Array::Create();
608         if (pArray == NULL) {
609           return FALSE;
610         }
611         FX_BOOL bSelected;
612         int iCount = CountOptions();
613         for (int i = 0; i < iCount; i++) {
614           if (i != index) {
615             bSelected = IsItemSelected(i);
616           } else {
617             bSelected = TRUE;
618           }
619           if (bSelected) {
620             opt_value = GetOptionValue(i);
621             pArray->AddString(PDF_EncodeText(opt_value));
622           }
623         }
624         m_pDict->SetAt("V", pArray);
625       }
626     } else if (m_Type == ComboBox) {
627       m_pDict->SetAtString("V", PDF_EncodeText(opt_value));
628       CPDF_Array* pI = CPDF_Array::Create();
629       if (pI == NULL) {
630         return FALSE;
631       }
632       pI->AddInteger(index);
633       m_pDict->SetAt("I", pI);
634     }
635   }
636   if (bNotify && m_pForm->m_pFormNotify != NULL) {
637     if (GetType() == ListBox) {
638       m_pForm->m_pFormNotify->AfterSelectionChange(this);
639     }
640     if (GetType() == ComboBox) {
641       m_pForm->m_pFormNotify->AfterValueChange(this);
642     }
643   }
644   if (CPDF_InterForm::m_bUpdateAP) {
645     UpdateAP(NULL);
646   }
647   m_pForm->m_bUpdated = TRUE;
648   return TRUE;
649 }
650 FX_BOOL CPDF_FormField::IsItemDefaultSelected(int index) {
651   ASSERT(GetType() == ComboBox || GetType() == ListBox);
652   if (index < 0 || index >= CountOptions()) {
653     return FALSE;
654   }
655   int iDVIndex = GetDefaultSelectedItem();
656   if (iDVIndex < 0) {
657     return FALSE;
658   }
659   return (iDVIndex == index);
660 }
661 int CPDF_FormField::GetDefaultSelectedItem() {
662   ASSERT(GetType() == ComboBox || GetType() == ListBox);
663   CPDF_Object* pValue = FPDF_GetFieldAttr(m_pDict, "DV");
664   if (pValue == NULL) {
665     return -1;
666   }
667   CFX_WideString csDV = pValue->GetUnicodeText();
668   if (csDV.IsEmpty()) {
669     return -1;
670   }
671   int iCount = CountOptions();
672   for (int i = 0; i < iCount; i++) {
673     if (csDV == GetOptionValue(i)) {
674       return i;
675     }
676   }
677   return -1;
678 }
679 void CPDF_FormField::UpdateAP(CPDF_FormControl* pControl) {
680   if (m_Type == PushButton) {
681     return;
682   }
683   if (m_Type == RadioButton || m_Type == CheckBox) {
684     return;
685   }
686   if (!m_pForm->m_bGenerateAP) {
687     return;
688   }
689   for (int i = 0; i < CountControls(); i++) {
690     CPDF_FormControl* pControl = GetControl(i);
691     FPDF_GenerateAP(m_pForm->m_pDocument, pControl->m_pWidgetDict);
692   }
693 }
694 int CPDF_FormField::CountOptions() {
695   CPDF_Array* pArray = ToArray(FPDF_GetFieldAttr(m_pDict, "Opt"));
696   return pArray ? pArray->GetCount() : 0;
697 }
698 CFX_WideString CPDF_FormField::GetOptionText(int index, int sub_index) {
699   CPDF_Array* pArray = ToArray(FPDF_GetFieldAttr(m_pDict, "Opt"));
700   if (!pArray)
701     return CFX_WideString();
702
703   CPDF_Object* pOption = pArray->GetElementValue(index);
704   if (!pOption)
705     return CFX_WideString();
706   if (CPDF_Array* pOptionArray = pOption->AsArray())
707     pOption = pOptionArray->GetElementValue(sub_index);
708
709   CPDF_String* pString = ToString(pOption);
710   return pString ? pString->GetUnicodeText() : CFX_WideString();
711 }
712 CFX_WideString CPDF_FormField::GetOptionLabel(int index) {
713   return GetOptionText(index, 1);
714 }
715 CFX_WideString CPDF_FormField::GetOptionValue(int index) {
716   return GetOptionText(index, 0);
717 }
718 int CPDF_FormField::FindOption(CFX_WideString csOptLabel) {
719   int iCount = CountOptions();
720   for (int i = 0; i < iCount; i++) {
721     CFX_WideString csValue = GetOptionValue(i);
722     if (csValue == csOptLabel) {
723       return i;
724     }
725   }
726   return -1;
727 }
728 int CPDF_FormField::FindOptionValue(const CFX_WideString& csOptValue,
729                                     int iStartIndex) {
730   if (iStartIndex < 0) {
731     iStartIndex = 0;
732   }
733   int iCount = CountOptions();
734   for (; iStartIndex < iCount; iStartIndex++) {
735     CFX_WideString csValue = GetOptionValue(iStartIndex);
736     if (csValue == csOptValue) {
737       return iStartIndex;
738     }
739   }
740   return -1;
741 }
742 FX_BOOL CPDF_FormField::CheckControl(int iControlIndex,
743                                      FX_BOOL bChecked,
744                                      FX_BOOL bNotify) {
745   ASSERT(GetType() == CheckBox || GetType() == RadioButton);
746   CPDF_FormControl* pControl = GetControl(iControlIndex);
747   if (pControl == NULL) {
748     return FALSE;
749   }
750   if (!bChecked && pControl->IsChecked() == bChecked) {
751     return FALSE;
752   }
753   CFX_ByteArray statusArray;
754   if (bNotify && m_pForm->m_pFormNotify != NULL) {
755     SaveCheckedFieldStatus(this, statusArray);
756   }
757   CFX_WideString csWExport = pControl->GetExportValue();
758   CFX_ByteString csBExport = PDF_EncodeText(csWExport);
759   int iCount = CountControls();
760   FX_BOOL bUnison = PDF_FormField_IsUnison(this);
761   for (int i = 0; i < iCount; i++) {
762     CPDF_FormControl* pCtrl = GetControl(i);
763     if (bUnison) {
764       CFX_WideString csEValue = pCtrl->GetExportValue();
765       if (csEValue == csWExport) {
766         if (pCtrl->GetOnStateName() == pControl->GetOnStateName()) {
767           pCtrl->CheckControl(bChecked);
768         } else if (bChecked) {
769           pCtrl->CheckControl(FALSE);
770         }
771       } else if (bChecked) {
772         pCtrl->CheckControl(FALSE);
773       }
774     } else {
775       if (i == iControlIndex) {
776         pCtrl->CheckControl(bChecked);
777       } else if (bChecked) {
778         pCtrl->CheckControl(FALSE);
779       }
780     }
781   }
782   CPDF_Object* pOpt = FPDF_GetFieldAttr(m_pDict, "Opt");
783   if (!ToArray(pOpt)) {
784     if (bChecked) {
785       m_pDict->SetAtName("V", csBExport);
786     } else {
787       CFX_ByteString csV;
788       CPDF_Object* pV = FPDF_GetFieldAttr(m_pDict, "V");
789       if (pV != NULL) {
790         csV = pV->GetString();
791       }
792       if (csV == csBExport) {
793         m_pDict->SetAtName("V", "Off");
794       }
795     }
796   } else if (bChecked) {
797     CFX_ByteString csIndex;
798     csIndex.Format("%d", iControlIndex);
799     m_pDict->SetAtName("V", csIndex);
800   }
801   if (bNotify && m_pForm->m_pFormNotify != NULL) {
802     m_pForm->m_pFormNotify->AfterCheckedStatusChange(this, statusArray);
803   }
804   m_pForm->m_bUpdated = TRUE;
805   return TRUE;
806 }
807 CFX_WideString CPDF_FormField::GetCheckValue(FX_BOOL bDefault) {
808   ASSERT(GetType() == CheckBox || GetType() == RadioButton);
809   CFX_WideString csExport = L"Off";
810   FX_BOOL bChecked;
811   int iCount = CountControls();
812   for (int i = 0; i < iCount; i++) {
813     CPDF_FormControl* pControl = GetControl(i);
814     if (bDefault) {
815       bChecked = pControl->IsDefaultChecked();
816     } else {
817       bChecked = pControl->IsChecked();
818     }
819     if (bChecked) {
820       csExport = pControl->GetExportValue();
821       break;
822     }
823   }
824   return csExport;
825 }
826 FX_BOOL CPDF_FormField::SetCheckValue(const CFX_WideString& value,
827                                       FX_BOOL bDefault,
828                                       FX_BOOL bNotify) {
829   ASSERT(GetType() == CheckBox || GetType() == RadioButton);
830   CFX_ByteArray statusArray;
831   if (bNotify && m_pForm->m_pFormNotify != NULL) {
832     SaveCheckedFieldStatus(this, statusArray);
833   }
834   int iCount = CountControls();
835   for (int i = 0; i < iCount; i++) {
836     CPDF_FormControl* pControl = GetControl(i);
837     CFX_WideString csExport = pControl->GetExportValue();
838     if (csExport == value) {
839       if (bDefault) {
840       } else {
841         CheckControl(GetControlIndex(pControl), TRUE);
842       }
843       break;
844     } else {
845       if (bDefault) {
846       } else {
847         CheckControl(GetControlIndex(pControl), FALSE);
848       }
849     }
850   }
851   if (bNotify && m_pForm->m_pFormNotify != NULL) {
852     m_pForm->m_pFormNotify->AfterCheckedStatusChange(this, statusArray);
853   }
854   m_pForm->m_bUpdated = TRUE;
855   return TRUE;
856 }
857 int CPDF_FormField::GetTopVisibleIndex() {
858   CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict, "TI");
859   if (pObj == NULL) {
860     return 0;
861   }
862   return pObj->GetInteger();
863 }
864 int CPDF_FormField::CountSelectedOptions() {
865   CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict, "I");
866   if (pObj == NULL) {
867     return 0;
868   }
869   CPDF_Array* pArray = pObj->GetArray();
870   if (pArray == NULL) {
871     return 0;
872   }
873   return (int)pArray->GetCount();
874 }
875 int CPDF_FormField::GetSelectedOptionIndex(int index) {
876   CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict, "I");
877   if (pObj == NULL) {
878     return -1;
879   }
880   CPDF_Array* pArray = pObj->GetArray();
881   if (pArray == NULL) {
882     return -1;
883   }
884   int iCount = (int)pArray->GetCount();
885   if (iCount > 0 && index < iCount) {
886     return pArray->GetInteger(index);
887   }
888   return -1;
889 }
890 FX_BOOL CPDF_FormField::IsOptionSelected(int iOptIndex) {
891   CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict, "I");
892   if (pObj == NULL) {
893     return FALSE;
894   }
895   CPDF_Array* pArray = pObj->GetArray();
896   if (pArray == NULL) {
897     return FALSE;
898   }
899   int iCount = (int)pArray->GetCount();
900   for (int i = 0; i < iCount; i++) {
901     if (pArray->GetInteger(i) == iOptIndex) {
902       return TRUE;
903     }
904   }
905   return FALSE;
906 }
907 FX_BOOL CPDF_FormField::SelectOption(int iOptIndex,
908                                      FX_BOOL bSelected,
909                                      FX_BOOL bNotify) {
910   CPDF_Array* pArray = m_pDict->GetArray("I");
911   if (pArray == NULL) {
912     if (!bSelected) {
913       return TRUE;
914     }
915     pArray = CPDF_Array::Create();
916     if (pArray == NULL) {
917       return FALSE;
918     }
919     m_pDict->SetAt("I", pArray);
920   }
921   FX_BOOL bReturn = FALSE;
922   for (int i = 0; i < (int)pArray->GetCount(); i++) {
923     int iFind = pArray->GetInteger(i);
924     if (iFind == iOptIndex) {
925       if (bSelected) {
926         return TRUE;
927       }
928       if (bNotify && m_pForm->m_pFormNotify != NULL) {
929         int iRet = 0;
930         CFX_WideString csValue = GetOptionLabel(iOptIndex);
931         if (GetType() == ListBox) {
932           iRet = m_pForm->m_pFormNotify->BeforeSelectionChange(this, csValue);
933         }
934         if (GetType() == ComboBox) {
935           iRet = m_pForm->m_pFormNotify->BeforeValueChange(this, csValue);
936         }
937         if (iRet < 0) {
938           return FALSE;
939         }
940       }
941       pArray->RemoveAt(i);
942       bReturn = TRUE;
943       break;
944     } else if (iFind > iOptIndex) {
945       if (!bSelected) {
946         continue;
947       }
948       if (bNotify && m_pForm->m_pFormNotify != NULL) {
949         int iRet = 0;
950         CFX_WideString csValue = GetOptionLabel(iOptIndex);
951         if (GetType() == ListBox) {
952           iRet = m_pForm->m_pFormNotify->BeforeSelectionChange(this, csValue);
953         }
954         if (GetType() == ComboBox) {
955           iRet = m_pForm->m_pFormNotify->BeforeValueChange(this, csValue);
956         }
957         if (iRet < 0) {
958           return FALSE;
959         }
960       }
961       CPDF_Number* pNum = CPDF_Number::Create(iOptIndex);
962       if (pNum == NULL) {
963         return FALSE;
964       }
965       pArray->InsertAt(i, pNum);
966       bReturn = TRUE;
967       break;
968     }
969   }
970   if (!bReturn) {
971     if (bSelected) {
972       pArray->AddInteger(iOptIndex);
973     }
974     if (pArray->GetCount() == 0) {
975       m_pDict->RemoveAt("I");
976     }
977   }
978   if (bNotify && m_pForm->m_pFormNotify != NULL) {
979     if (GetType() == ListBox) {
980       m_pForm->m_pFormNotify->AfterSelectionChange(this);
981     }
982     if (GetType() == ComboBox) {
983       m_pForm->m_pFormNotify->AfterValueChange(this);
984     }
985   }
986   m_pForm->m_bUpdated = TRUE;
987   return TRUE;
988 }
989 FX_BOOL CPDF_FormField::ClearSelectedOptions(FX_BOOL bNotify) {
990   if (bNotify && m_pForm->m_pFormNotify != NULL) {
991     int iRet = 0;
992     CFX_WideString csValue;
993     int iIndex = GetSelectedIndex(0);
994     if (iIndex >= 0) {
995       csValue = GetOptionLabel(iIndex);
996     }
997     if (GetType() == ListBox) {
998       iRet = m_pForm->m_pFormNotify->BeforeSelectionChange(this, csValue);
999     }
1000     if (GetType() == ComboBox) {
1001       iRet = m_pForm->m_pFormNotify->BeforeValueChange(this, csValue);
1002     }
1003     if (iRet < 0) {
1004       return FALSE;
1005     }
1006   }
1007   m_pDict->RemoveAt("I");
1008   if (bNotify && m_pForm->m_pFormNotify != NULL) {
1009     if (GetType() == ListBox) {
1010       m_pForm->m_pFormNotify->AfterSelectionChange(this);
1011     }
1012     if (GetType() == ComboBox) {
1013       m_pForm->m_pFormNotify->AfterValueChange(this);
1014     }
1015   }
1016   m_pForm->m_bUpdated = TRUE;
1017   return TRUE;
1018 }
1019 void CPDF_FormField::LoadDA() {
1020   CFX_ByteString DA;
1021   if (CPDF_Object* pObj_t = FPDF_GetFieldAttr(m_pDict, "DA")) {
1022     DA = pObj_t->GetString();
1023   }
1024   if (DA.IsEmpty() && m_pForm->m_pFormDict) {
1025     DA = m_pForm->m_pFormDict->GetString("DA");
1026   }
1027   if (DA.IsEmpty()) {
1028     return;
1029   }
1030   CPDF_SimpleParser syntax(DA);
1031   syntax.FindTagParam("Tf", 2);
1032   CFX_ByteString font_name = syntax.GetWord();
1033   CPDF_Dictionary* pFontDict = NULL;
1034   if (m_pForm->m_pFormDict && m_pForm->m_pFormDict->GetDict("DR") &&
1035       m_pForm->m_pFormDict->GetDict("DR")->GetDict("Font"))
1036     pFontDict = m_pForm->m_pFormDict->GetDict("DR")->GetDict("Font")->GetDict(
1037         font_name);
1038
1039   if (pFontDict == NULL) {
1040     return;
1041   }
1042   m_pFont = m_pForm->m_pDocument->LoadFont(pFontDict);
1043   m_FontSize = FX_atof(syntax.GetWord());
1044 }