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