Add new public APIs to find the z-order for links and widgets.
[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 = ((CPDF_Array*)pValue)->GetElementValue(0);
311       if (pValue) {
312         return pValue->GetUnicodeText();
313       }
314       break;
315   }
316   return CFX_WideString();
317 }
318 CFX_WideString CPDF_FormField::GetValue() {
319   return GetValue(FALSE);
320 }
321 CFX_WideString CPDF_FormField::GetDefaultValue() {
322   return GetValue(TRUE);
323 }
324 FX_BOOL CPDF_FormField::SetValue(const CFX_WideString& value,
325                                  FX_BOOL bDefault,
326                                  FX_BOOL bNotify) {
327   switch (m_Type) {
328     case CheckBox:
329     case RadioButton: {
330       SetCheckValue(value, bDefault, bNotify);
331       return TRUE;
332     }
333     case File:
334     case RichText:
335     case Text:
336     case ComboBox: {
337       CFX_WideString csValue = value;
338       if (bNotify && m_pForm->m_pFormNotify != NULL) {
339         int iRet = m_pForm->m_pFormNotify->BeforeValueChange(this, csValue);
340         if (iRet < 0) {
341           return FALSE;
342         }
343       }
344       int iIndex = FindOptionValue(csValue);
345       if (iIndex < 0) {
346         CFX_ByteString bsEncodeText = PDF_EncodeText(csValue);
347         m_pDict->SetAtString(bDefault ? "DV" : "V", bsEncodeText);
348         if (m_Type == RichText && !bDefault) {
349           m_pDict->SetAtString("RV", bsEncodeText);
350         }
351         m_pDict->RemoveAt("I");
352       } else {
353         m_pDict->SetAtString(bDefault ? "DV" : "V", PDF_EncodeText(csValue));
354         if (bDefault) {
355         } else {
356           ClearSelection();
357           SetItemSelection(iIndex, TRUE);
358         }
359       }
360       if (bNotify && m_pForm->m_pFormNotify != NULL) {
361         m_pForm->m_pFormNotify->AfterValueChange(this);
362       }
363       m_pForm->m_bUpdated = TRUE;
364     } break;
365     case ListBox: {
366       int iIndex = FindOptionValue(value);
367       if (iIndex < 0) {
368         return FALSE;
369       }
370       if (bDefault && iIndex == GetDefaultSelectedItem()) {
371         return FALSE;
372       }
373       if (bNotify && m_pForm->m_pFormNotify != NULL) {
374         CFX_WideString csValue = value;
375         int iRet = m_pForm->m_pFormNotify->BeforeSelectionChange(this, csValue);
376         if (iRet < 0) {
377           return FALSE;
378         }
379       }
380       if (bDefault) {
381       } else {
382         ClearSelection();
383         SetItemSelection(iIndex, TRUE);
384       }
385       if (bNotify && m_pForm->m_pFormNotify != NULL) {
386         m_pForm->m_pFormNotify->AfterSelectionChange(this);
387       }
388       m_pForm->m_bUpdated = TRUE;
389       break;
390     }
391     default:
392       break;
393   }
394   if (CPDF_InterForm::m_bUpdateAP) {
395     UpdateAP(NULL);
396   }
397   return TRUE;
398 }
399 FX_BOOL CPDF_FormField::SetValue(const CFX_WideString& value, FX_BOOL bNotify) {
400   return SetValue(value, FALSE, bNotify);
401 }
402 int CPDF_FormField::GetMaxLen() {
403   CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict, "MaxLen");
404   if (pObj == NULL) {
405     int iCount = m_ControlList.GetSize();
406     for (int i = 0; i < iCount; i++) {
407       CPDF_FormControl* pControl = (CPDF_FormControl*)m_ControlList.GetAt(i);
408       if (pControl == NULL) {
409         continue;
410       }
411       CPDF_Dictionary* pWidgetDict = pControl->m_pWidgetDict;
412       if (pWidgetDict->KeyExist("MaxLen")) {
413         return pWidgetDict->GetInteger("MaxLen");
414       }
415     }
416     return 0;
417   }
418   return pObj->GetInteger();
419 }
420 int CPDF_FormField::CountSelectedItems() {
421   CPDF_Object* pValue = FPDF_GetFieldAttr(m_pDict, "V");
422   if (pValue == NULL) {
423     pValue = FPDF_GetFieldAttr(m_pDict, "I");
424     if (pValue == NULL) {
425       return 0;
426     }
427   }
428   if (pValue->GetType() == PDFOBJ_STRING) {
429     if (pValue->GetString().IsEmpty()) {
430       return 0;
431     }
432     return 1;
433   }
434   if (pValue->GetType() == PDFOBJ_NUMBER) {
435     if (pValue->GetString().IsEmpty()) {
436       return 0;
437     }
438     return 1;
439   }
440   if (pValue->GetType() != PDFOBJ_ARRAY) {
441     return 0;
442   }
443   return ((CPDF_Array*)pValue)->GetCount();
444 }
445 int CPDF_FormField::GetSelectedIndex(int index) {
446   CPDF_Object* pValue = FPDF_GetFieldAttr(m_pDict, "V");
447   if (pValue == NULL) {
448     pValue = FPDF_GetFieldAttr(m_pDict, "I");
449     if (pValue == NULL) {
450       return -1;
451     }
452   }
453   if (pValue->GetType() == PDFOBJ_NUMBER) {
454     return pValue->GetInteger();
455   }
456   CFX_WideString sel_value;
457   if (pValue->GetType() == PDFOBJ_STRING) {
458     if (index != 0) {
459       return -1;
460     }
461     sel_value = pValue->GetUnicodeText();
462   } else {
463     if (pValue->GetType() != PDFOBJ_ARRAY) {
464       return -1;
465     }
466     if (index < 0) {
467       return -1;
468     }
469     CPDF_Object* elementValue = ((CPDF_Array*)pValue)->GetElementValue(index);
470     sel_value =
471         elementValue ? elementValue->GetUnicodeText() : CFX_WideString();
472   }
473   if (index < CountSelectedOptions()) {
474     int iOptIndex = GetSelectedOptionIndex(index);
475     CFX_WideString csOpt = GetOptionValue(iOptIndex);
476     if (csOpt == sel_value) {
477       return iOptIndex;
478     }
479   }
480   int nOpts = CountOptions();
481   for (int i = 0; i < nOpts; i++) {
482     if (sel_value == GetOptionValue(i)) {
483       return i;
484     }
485   }
486   return -1;
487 }
488 FX_BOOL CPDF_FormField::ClearSelection(FX_BOOL bNotify) {
489   if (bNotify && m_pForm->m_pFormNotify != NULL) {
490     int iRet = 0;
491     CFX_WideString csValue;
492     int iIndex = GetSelectedIndex(0);
493     if (iIndex >= 0) {
494       csValue = GetOptionLabel(iIndex);
495     }
496     if (GetType() == ListBox) {
497       iRet = m_pForm->m_pFormNotify->BeforeSelectionChange(this, csValue);
498     }
499     if (GetType() == ComboBox) {
500       iRet = m_pForm->m_pFormNotify->BeforeValueChange(this, csValue);
501     }
502     if (iRet < 0) {
503       return FALSE;
504     }
505   }
506   m_pDict->RemoveAt("V");
507   m_pDict->RemoveAt("I");
508   if (bNotify && m_pForm->m_pFormNotify != NULL) {
509     if (GetType() == ListBox) {
510       m_pForm->m_pFormNotify->AfterSelectionChange(this);
511     }
512     if (GetType() == ComboBox) {
513       m_pForm->m_pFormNotify->AfterValueChange(this);
514     }
515   }
516   if (CPDF_InterForm::m_bUpdateAP) {
517     UpdateAP(NULL);
518   }
519   m_pForm->m_bUpdated = TRUE;
520   return TRUE;
521 }
522 FX_BOOL CPDF_FormField::IsItemSelected(int index) {
523   ASSERT(GetType() == ComboBox || GetType() == ListBox);
524   if (index < 0 || index >= CountOptions()) {
525     return FALSE;
526   }
527   if (IsOptionSelected(index)) {
528     return TRUE;
529   }
530   CFX_WideString opt_value = GetOptionValue(index);
531   CPDF_Object* pValue = FPDF_GetFieldAttr(m_pDict, "V");
532   if (pValue == NULL) {
533     pValue = FPDF_GetFieldAttr(m_pDict, "I");
534     if (pValue == NULL) {
535       return FALSE;
536     }
537   }
538   if (pValue->GetType() == PDFOBJ_STRING) {
539     if (pValue->GetUnicodeText() == opt_value) {
540       return TRUE;
541     }
542     return FALSE;
543   }
544   if (pValue->GetType() == PDFOBJ_NUMBER) {
545     if (pValue->GetString().IsEmpty()) {
546       return FALSE;
547     }
548     if (pValue->GetInteger() == index) {
549       return TRUE;
550     }
551     return FALSE;
552   }
553   if (pValue->GetType() != PDFOBJ_ARRAY) {
554     return FALSE;
555   }
556   CPDF_Array* pArray = (CPDF_Array*)pValue;
557   int iPos = -1;
558   for (int j = 0; j < CountSelectedOptions(); j++) {
559     if (GetSelectedOptionIndex(j) == index) {
560       iPos = j;
561       break;
562     }
563   }
564   for (FX_DWORD i = 0; i < pArray->GetCount(); i++)
565     if (pArray->GetElementValue(i)->GetUnicodeText() == opt_value &&
566         (int)i == iPos) {
567       return TRUE;
568     }
569   return FALSE;
570 }
571 FX_BOOL CPDF_FormField::SetItemSelection(int index,
572                                          FX_BOOL bSelected,
573                                          FX_BOOL bNotify) {
574   ASSERT(GetType() == ComboBox || GetType() == ListBox);
575   if (index < 0 || index >= CountOptions()) {
576     return FALSE;
577   }
578   CFX_WideString opt_value = GetOptionValue(index);
579   if (bNotify && m_pForm->m_pFormNotify != NULL) {
580     int iRet = 0;
581     if (GetType() == ListBox) {
582       iRet = m_pForm->m_pFormNotify->BeforeSelectionChange(this, opt_value);
583     }
584     if (GetType() == ComboBox) {
585       iRet = m_pForm->m_pFormNotify->BeforeValueChange(this, opt_value);
586     }
587     if (iRet < 0) {
588       return FALSE;
589     }
590   }
591   if (!bSelected) {
592     CPDF_Object* pValue = FPDF_GetFieldAttr(m_pDict, "V");
593     if (pValue != NULL) {
594       if (m_Type == ListBox) {
595         SelectOption(index, FALSE);
596         if (pValue->GetType() == PDFOBJ_STRING) {
597           if (pValue->GetUnicodeText() == opt_value) {
598             m_pDict->RemoveAt("V");
599           }
600         } else if (pValue->GetType() == PDFOBJ_ARRAY) {
601           CPDF_Array* pArray = CPDF_Array::Create();
602           if (pArray == NULL) {
603             return FALSE;
604           }
605           int iCount = CountOptions();
606           for (int i = 0; i < iCount; i++) {
607             if (i != index) {
608               if (IsItemSelected(i)) {
609                 opt_value = GetOptionValue(i);
610                 pArray->AddString(PDF_EncodeText(opt_value));
611               }
612             }
613           }
614           if (pArray->GetCount() < 1) {
615             pArray->Release();
616           } else {
617             m_pDict->SetAt("V", pArray);
618           }
619         }
620       } else if (m_Type == ComboBox) {
621         m_pDict->RemoveAt("V");
622         m_pDict->RemoveAt("I");
623       }
624     }
625   } else {
626     if (m_Type == ListBox) {
627       SelectOption(index, TRUE);
628       if (!(m_Flags & FORMLIST_MULTISELECT)) {
629         m_pDict->SetAtString("V", PDF_EncodeText(opt_value));
630       } else {
631         CPDF_Array* pArray = CPDF_Array::Create();
632         if (pArray == NULL) {
633           return FALSE;
634         }
635         FX_BOOL bSelected;
636         int iCount = CountOptions();
637         for (int i = 0; i < iCount; i++) {
638           if (i != index) {
639             bSelected = IsItemSelected(i);
640           } else {
641             bSelected = TRUE;
642           }
643           if (bSelected) {
644             opt_value = GetOptionValue(i);
645             pArray->AddString(PDF_EncodeText(opt_value));
646           }
647         }
648         m_pDict->SetAt("V", pArray);
649       }
650     } else if (m_Type == ComboBox) {
651       m_pDict->SetAtString("V", PDF_EncodeText(opt_value));
652       CPDF_Array* pI = CPDF_Array::Create();
653       if (pI == NULL) {
654         return FALSE;
655       }
656       pI->AddInteger(index);
657       m_pDict->SetAt("I", pI);
658     }
659   }
660   if (bNotify && m_pForm->m_pFormNotify != NULL) {
661     if (GetType() == ListBox) {
662       m_pForm->m_pFormNotify->AfterSelectionChange(this);
663     }
664     if (GetType() == ComboBox) {
665       m_pForm->m_pFormNotify->AfterValueChange(this);
666     }
667   }
668   if (CPDF_InterForm::m_bUpdateAP) {
669     UpdateAP(NULL);
670   }
671   m_pForm->m_bUpdated = TRUE;
672   return TRUE;
673 }
674 FX_BOOL CPDF_FormField::IsItemDefaultSelected(int index) {
675   ASSERT(GetType() == ComboBox || GetType() == ListBox);
676   if (index < 0 || index >= CountOptions()) {
677     return FALSE;
678   }
679   int iDVIndex = GetDefaultSelectedItem();
680   if (iDVIndex < 0) {
681     return FALSE;
682   }
683   return (iDVIndex == index);
684 }
685 int CPDF_FormField::GetDefaultSelectedItem() {
686   ASSERT(GetType() == ComboBox || GetType() == ListBox);
687   CPDF_Object* pValue = FPDF_GetFieldAttr(m_pDict, "DV");
688   if (pValue == NULL) {
689     return -1;
690   }
691   CFX_WideString csDV = pValue->GetUnicodeText();
692   if (csDV.IsEmpty()) {
693     return -1;
694   }
695   int iCount = CountOptions();
696   for (int i = 0; i < iCount; i++) {
697     if (csDV == GetOptionValue(i)) {
698       return i;
699     }
700   }
701   return -1;
702 }
703 void CPDF_FormField::UpdateAP(CPDF_FormControl* pControl) {
704   if (m_Type == PushButton) {
705     return;
706   }
707   if (m_Type == RadioButton || m_Type == CheckBox) {
708     return;
709   }
710   if (!m_pForm->m_bGenerateAP) {
711     return;
712   }
713   for (int i = 0; i < CountControls(); i++) {
714     CPDF_FormControl* pControl = GetControl(i);
715     FPDF_GenerateAP(m_pForm->m_pDocument, pControl->m_pWidgetDict);
716   }
717 }
718 int CPDF_FormField::CountOptions() {
719   CPDF_Object* pValue = FPDF_GetFieldAttr(m_pDict, "Opt");
720   if (pValue == NULL || pValue->GetType() != PDFOBJ_ARRAY) {
721     return 0;
722   }
723   return ((CPDF_Array*)pValue)->GetCount();
724 }
725 CFX_WideString CPDF_FormField::GetOptionText(int index, int sub_index) {
726   CPDF_Object* pValue = FPDF_GetFieldAttr(m_pDict, "Opt");
727   if (pValue == NULL || pValue->GetType() != PDFOBJ_ARRAY) {
728     return CFX_WideString();
729   }
730   CPDF_Object* pOption = ((CPDF_Array*)pValue)->GetElementValue(index);
731   if (pOption == NULL) {
732     return CFX_WideString();
733   }
734   if (pOption->GetType() == PDFOBJ_ARRAY) {
735     pOption = ((CPDF_Array*)pOption)->GetElementValue(sub_index);
736   }
737   if (pOption == NULL || pOption->GetType() != PDFOBJ_STRING) {
738     return CFX_WideString();
739   }
740   return ((CPDF_String*)pOption)->GetUnicodeText();
741 }
742 CFX_WideString CPDF_FormField::GetOptionLabel(int index) {
743   return GetOptionText(index, 1);
744 }
745 CFX_WideString CPDF_FormField::GetOptionValue(int index) {
746   return GetOptionText(index, 0);
747 }
748 int CPDF_FormField::FindOption(CFX_WideString csOptLabel) {
749   int iCount = CountOptions();
750   for (int i = 0; i < iCount; i++) {
751     CFX_WideString csValue = GetOptionValue(i);
752     if (csValue == csOptLabel) {
753       return i;
754     }
755   }
756   return -1;
757 }
758 int CPDF_FormField::FindOptionValue(const CFX_WideString& csOptValue,
759                                     int iStartIndex) {
760   if (iStartIndex < 0) {
761     iStartIndex = 0;
762   }
763   int iCount = CountOptions();
764   for (; iStartIndex < iCount; iStartIndex++) {
765     CFX_WideString csValue = GetOptionValue(iStartIndex);
766     if (csValue == csOptValue) {
767       return iStartIndex;
768     }
769   }
770   return -1;
771 }
772 FX_BOOL CPDF_FormField::CheckControl(int iControlIndex,
773                                      FX_BOOL bChecked,
774                                      FX_BOOL bNotify) {
775   ASSERT(GetType() == CheckBox || GetType() == RadioButton);
776   CPDF_FormControl* pControl = GetControl(iControlIndex);
777   if (pControl == NULL) {
778     return FALSE;
779   }
780   if (!bChecked && pControl->IsChecked() == bChecked) {
781     return FALSE;
782   }
783   CFX_ByteArray statusArray;
784   if (bNotify && m_pForm->m_pFormNotify != NULL) {
785     SaveCheckedFieldStatus(this, statusArray);
786   }
787   CFX_WideString csWExport = pControl->GetExportValue();
788   CFX_ByteString csBExport = PDF_EncodeText(csWExport);
789   int iCount = CountControls();
790   FX_BOOL bUnison = PDF_FormField_IsUnison(this);
791   for (int i = 0; i < iCount; i++) {
792     CPDF_FormControl* pCtrl = GetControl(i);
793     if (bUnison) {
794       CFX_WideString csEValue = pCtrl->GetExportValue();
795       if (csEValue == csWExport) {
796         if (pCtrl->GetOnStateName() == pControl->GetOnStateName()) {
797           pCtrl->CheckControl(bChecked);
798         } else if (bChecked) {
799           pCtrl->CheckControl(FALSE);
800         }
801       } else if (bChecked) {
802         pCtrl->CheckControl(FALSE);
803       }
804     } else {
805       if (i == iControlIndex) {
806         pCtrl->CheckControl(bChecked);
807       } else if (bChecked) {
808         pCtrl->CheckControl(FALSE);
809       }
810     }
811   }
812   CPDF_Object* pOpt = FPDF_GetFieldAttr(m_pDict, "Opt");
813   if (pOpt == NULL || pOpt->GetType() != PDFOBJ_ARRAY) {
814     if (bChecked) {
815       m_pDict->SetAtName("V", csBExport);
816     } else {
817       CFX_ByteString csV;
818       CPDF_Object* pV = FPDF_GetFieldAttr(m_pDict, "V");
819       if (pV != NULL) {
820         csV = pV->GetString();
821       }
822       if (csV == csBExport) {
823         m_pDict->SetAtName("V", "Off");
824       }
825     }
826   } else if (bChecked) {
827     CFX_ByteString csIndex;
828     csIndex.Format("%d", iControlIndex);
829     m_pDict->SetAtName("V", csIndex);
830   }
831   if (bNotify && m_pForm->m_pFormNotify != NULL) {
832     m_pForm->m_pFormNotify->AfterCheckedStatusChange(this, statusArray);
833   }
834   m_pForm->m_bUpdated = TRUE;
835   return TRUE;
836 }
837 CFX_WideString CPDF_FormField::GetCheckValue(FX_BOOL bDefault) {
838   ASSERT(GetType() == CheckBox || GetType() == RadioButton);
839   CFX_WideString csExport = L"Off";
840   FX_BOOL bChecked;
841   int iCount = CountControls();
842   for (int i = 0; i < iCount; i++) {
843     CPDF_FormControl* pControl = GetControl(i);
844     if (bDefault) {
845       bChecked = pControl->IsDefaultChecked();
846     } else {
847       bChecked = pControl->IsChecked();
848     }
849     if (bChecked) {
850       csExport = pControl->GetExportValue();
851       break;
852     }
853   }
854   return csExport;
855 }
856 FX_BOOL CPDF_FormField::SetCheckValue(const CFX_WideString& value,
857                                       FX_BOOL bDefault,
858                                       FX_BOOL bNotify) {
859   ASSERT(GetType() == CheckBox || GetType() == RadioButton);
860   CFX_ByteArray statusArray;
861   if (bNotify && m_pForm->m_pFormNotify != NULL) {
862     SaveCheckedFieldStatus(this, statusArray);
863   }
864   int iCount = CountControls();
865   for (int i = 0; i < iCount; i++) {
866     CPDF_FormControl* pControl = GetControl(i);
867     CFX_WideString csExport = pControl->GetExportValue();
868     if (csExport == value) {
869       if (bDefault) {
870       } else {
871         CheckControl(GetControlIndex(pControl), TRUE);
872       }
873       break;
874     } else {
875       if (bDefault) {
876       } else {
877         CheckControl(GetControlIndex(pControl), FALSE);
878       }
879     }
880   }
881   if (bNotify && m_pForm->m_pFormNotify != NULL) {
882     m_pForm->m_pFormNotify->AfterCheckedStatusChange(this, statusArray);
883   }
884   m_pForm->m_bUpdated = TRUE;
885   return TRUE;
886 }
887 int CPDF_FormField::GetTopVisibleIndex() {
888   CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict, "TI");
889   if (pObj == NULL) {
890     return 0;
891   }
892   return pObj->GetInteger();
893 }
894 int CPDF_FormField::CountSelectedOptions() {
895   CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict, "I");
896   if (pObj == NULL) {
897     return 0;
898   }
899   CPDF_Array* pArray = pObj->GetArray();
900   if (pArray == NULL) {
901     return 0;
902   }
903   return (int)pArray->GetCount();
904 }
905 int CPDF_FormField::GetSelectedOptionIndex(int index) {
906   CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict, "I");
907   if (pObj == NULL) {
908     return -1;
909   }
910   CPDF_Array* pArray = pObj->GetArray();
911   if (pArray == NULL) {
912     return -1;
913   }
914   int iCount = (int)pArray->GetCount();
915   if (iCount > 0 && index < iCount) {
916     return pArray->GetInteger(index);
917   }
918   return -1;
919 }
920 FX_BOOL CPDF_FormField::IsOptionSelected(int iOptIndex) {
921   CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict, "I");
922   if (pObj == NULL) {
923     return FALSE;
924   }
925   CPDF_Array* pArray = pObj->GetArray();
926   if (pArray == NULL) {
927     return FALSE;
928   }
929   int iCount = (int)pArray->GetCount();
930   for (int i = 0; i < iCount; i++) {
931     if (pArray->GetInteger(i) == iOptIndex) {
932       return TRUE;
933     }
934   }
935   return FALSE;
936 }
937 FX_BOOL CPDF_FormField::SelectOption(int iOptIndex,
938                                      FX_BOOL bSelected,
939                                      FX_BOOL bNotify) {
940   CPDF_Array* pArray = m_pDict->GetArray("I");
941   if (pArray == NULL) {
942     if (!bSelected) {
943       return TRUE;
944     }
945     pArray = CPDF_Array::Create();
946     if (pArray == NULL) {
947       return FALSE;
948     }
949     m_pDict->SetAt("I", pArray);
950   }
951   FX_BOOL bReturn = FALSE;
952   for (int i = 0; i < (int)pArray->GetCount(); i++) {
953     int iFind = pArray->GetInteger(i);
954     if (iFind == iOptIndex) {
955       if (bSelected) {
956         return TRUE;
957       }
958       if (bNotify && m_pForm->m_pFormNotify != NULL) {
959         int iRet = 0;
960         CFX_WideString csValue = GetOptionLabel(iOptIndex);
961         if (GetType() == ListBox) {
962           iRet = m_pForm->m_pFormNotify->BeforeSelectionChange(this, csValue);
963         }
964         if (GetType() == ComboBox) {
965           iRet = m_pForm->m_pFormNotify->BeforeValueChange(this, csValue);
966         }
967         if (iRet < 0) {
968           return FALSE;
969         }
970       }
971       pArray->RemoveAt(i);
972       bReturn = TRUE;
973       break;
974     } else if (iFind > iOptIndex) {
975       if (!bSelected) {
976         continue;
977       }
978       if (bNotify && m_pForm->m_pFormNotify != NULL) {
979         int iRet = 0;
980         CFX_WideString csValue = GetOptionLabel(iOptIndex);
981         if (GetType() == ListBox) {
982           iRet = m_pForm->m_pFormNotify->BeforeSelectionChange(this, csValue);
983         }
984         if (GetType() == ComboBox) {
985           iRet = m_pForm->m_pFormNotify->BeforeValueChange(this, csValue);
986         }
987         if (iRet < 0) {
988           return FALSE;
989         }
990       }
991       CPDF_Number* pNum = CPDF_Number::Create(iOptIndex);
992       if (pNum == NULL) {
993         return FALSE;
994       }
995       pArray->InsertAt(i, pNum);
996       bReturn = TRUE;
997       break;
998     }
999   }
1000   if (!bReturn) {
1001     if (bSelected) {
1002       pArray->AddInteger(iOptIndex);
1003     }
1004     if (pArray->GetCount() == 0) {
1005       m_pDict->RemoveAt("I");
1006     }
1007   }
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 FX_BOOL CPDF_FormField::ClearSelectedOptions(FX_BOOL bNotify) {
1020   if (bNotify && m_pForm->m_pFormNotify != NULL) {
1021     int iRet = 0;
1022     CFX_WideString csValue;
1023     int iIndex = GetSelectedIndex(0);
1024     if (iIndex >= 0) {
1025       csValue = GetOptionLabel(iIndex);
1026     }
1027     if (GetType() == ListBox) {
1028       iRet = m_pForm->m_pFormNotify->BeforeSelectionChange(this, csValue);
1029     }
1030     if (GetType() == ComboBox) {
1031       iRet = m_pForm->m_pFormNotify->BeforeValueChange(this, csValue);
1032     }
1033     if (iRet < 0) {
1034       return FALSE;
1035     }
1036   }
1037   m_pDict->RemoveAt("I");
1038   if (bNotify && m_pForm->m_pFormNotify != NULL) {
1039     if (GetType() == ListBox) {
1040       m_pForm->m_pFormNotify->AfterSelectionChange(this);
1041     }
1042     if (GetType() == ComboBox) {
1043       m_pForm->m_pFormNotify->AfterValueChange(this);
1044     }
1045   }
1046   m_pForm->m_bUpdated = TRUE;
1047   return TRUE;
1048 }
1049 void CPDF_FormField::LoadDA() {
1050   CFX_ByteString DA;
1051   if (CPDF_Object* pObj_t = FPDF_GetFieldAttr(m_pDict, "DA")) {
1052     DA = pObj_t->GetString();
1053   }
1054   if (DA.IsEmpty() && m_pForm->m_pFormDict) {
1055     DA = m_pForm->m_pFormDict->GetString("DA");
1056   }
1057   if (DA.IsEmpty()) {
1058     return;
1059   }
1060   CPDF_SimpleParser syntax(DA);
1061   syntax.FindTagParam("Tf", 2);
1062   CFX_ByteString font_name = syntax.GetWord();
1063   CPDF_Dictionary* pFontDict = NULL;
1064   if (m_pForm->m_pFormDict && m_pForm->m_pFormDict->GetDict("DR") &&
1065       m_pForm->m_pFormDict->GetDict("DR")->GetDict("Font"))
1066     pFontDict = m_pForm->m_pFormDict->GetDict("DR")->GetDict("Font")->GetDict(
1067         font_name);
1068
1069   if (pFontDict == NULL) {
1070     return;
1071   }
1072   m_pFont = m_pForm->m_pDocument->LoadFont(pFontDict);
1073   m_FontSize = FX_atof(syntax.GetWord());
1074 }