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