summaryrefslogtreecommitdiff
path: root/core/fpdfdoc/cpdf_formfield.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'core/fpdfdoc/cpdf_formfield.cpp')
-rw-r--r--core/fpdfdoc/cpdf_formfield.cpp997
1 files changed, 997 insertions, 0 deletions
diff --git a/core/fpdfdoc/cpdf_formfield.cpp b/core/fpdfdoc/cpdf_formfield.cpp
new file mode 100644
index 0000000000..81d2178820
--- /dev/null
+++ b/core/fpdfdoc/cpdf_formfield.cpp
@@ -0,0 +1,997 @@
+// Copyright 2014 PDFium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
+
+#include "core/fpdfdoc/include/cpdf_formfield.h"
+
+#include "core/fpdfapi/fpdf_parser/include/cfdf_document.h"
+#include "core/fpdfapi/fpdf_parser/include/cpdf_array.h"
+#include "core/fpdfapi/fpdf_parser/include/cpdf_document.h"
+#include "core/fpdfapi/fpdf_parser/include/cpdf_number.h"
+#include "core/fpdfapi/fpdf_parser/include/cpdf_simple_parser.h"
+#include "core/fpdfapi/fpdf_parser/include/cpdf_string.h"
+#include "core/fpdfapi/fpdf_parser/include/fpdf_parser_decode.h"
+#include "core/fpdfdoc/cpvt_generateap.h"
+#include "core/fpdfdoc/include/cpdf_formcontrol.h"
+#include "core/fpdfdoc/include/cpdf_interform.h"
+
+namespace {
+
+const int kMaxRecursion = 32;
+
+const int kFormListMultiSelect = 0x100;
+
+const int kFormComboEdit = 0x100;
+
+const int kFormFieldReadOnly = 0x01;
+const int kFormFieldRequired = 0x02;
+const int kFormFieldNoExport = 0x04;
+
+const int kFormRadioNoToggleOff = 0x100;
+const int kFormRadioUnison = 0x200;
+
+const int kFormTextMultiLine = 0x100;
+const int kFormTextPassword = 0x200;
+const int kFormTextNoScroll = 0x400;
+const int kFormTextComb = 0x800;
+
+bool IsUnison(CPDF_FormField* pField) {
+ if (pField->GetType() == CPDF_FormField::CheckBox)
+ return true;
+ return (pField->GetFieldFlags() & 0x2000000) != 0;
+}
+
+} // namespace
+
+CPDF_Object* FPDF_GetFieldAttr(CPDF_Dictionary* pFieldDict,
+ const FX_CHAR* name,
+ int nLevel) {
+ if (nLevel > kMaxRecursion)
+ return nullptr;
+ if (!pFieldDict)
+ return nullptr;
+
+ CPDF_Object* pAttr = pFieldDict->GetDirectObjectBy(name);
+ if (pAttr)
+ return pAttr;
+
+ CPDF_Dictionary* pParent = pFieldDict->GetDictBy("Parent");
+ if (!pParent)
+ return nullptr;
+ return FPDF_GetFieldAttr(pParent, name, nLevel + 1);
+}
+
+CFX_WideString FPDF_GetFullName(CPDF_Dictionary* pFieldDict) {
+ CFX_WideString full_name;
+ CPDF_Dictionary* pLevel = pFieldDict;
+ while (pLevel) {
+ CFX_WideString short_name = pLevel->GetUnicodeTextBy("T");
+ if (short_name != L"") {
+ if (full_name == L"")
+ full_name = short_name;
+ else
+ full_name = short_name + L"." + full_name;
+ }
+ pLevel = pLevel->GetDictBy("Parent");
+ }
+ return full_name;
+}
+
+CPDF_FormField::CPDF_FormField(CPDF_InterForm* pForm, CPDF_Dictionary* pDict)
+ : m_Type(Unknown),
+ m_pForm(pForm),
+ m_pDict(pDict),
+ m_FontSize(0),
+ m_pFont(nullptr) {
+ SyncFieldFlags();
+}
+
+CPDF_FormField::~CPDF_FormField() {}
+
+void CPDF_FormField::SyncFieldFlags() {
+ CFX_ByteString type_name = FPDF_GetFieldAttr(m_pDict, "FT")
+ ? FPDF_GetFieldAttr(m_pDict, "FT")->GetString()
+ : CFX_ByteString();
+ uint32_t flags = FPDF_GetFieldAttr(m_pDict, "Ff")
+ ? FPDF_GetFieldAttr(m_pDict, "Ff")->GetInteger()
+ : 0;
+ m_Flags = 0;
+ if (flags & 1)
+ m_Flags |= kFormFieldReadOnly;
+ if (flags & 2)
+ m_Flags |= kFormFieldRequired;
+ if (flags & 4)
+ m_Flags |= kFormFieldNoExport;
+
+ if (type_name == "Btn") {
+ if (flags & 0x8000) {
+ m_Type = RadioButton;
+ if (flags & 0x4000)
+ m_Flags |= kFormRadioNoToggleOff;
+ if (flags & 0x2000000)
+ m_Flags |= kFormRadioUnison;
+ } else if (flags & 0x10000) {
+ m_Type = PushButton;
+ } else {
+ m_Type = CheckBox;
+ }
+ } else if (type_name == "Tx") {
+ if (flags & 0x100000) {
+ m_Type = File;
+ } else if (flags & 0x2000000) {
+ m_Type = RichText;
+ } else {
+ m_Type = Text;
+ if (flags & 0x1000)
+ m_Flags |= kFormTextMultiLine;
+ if (flags & 0x2000)
+ m_Flags |= kFormTextPassword;
+ if (flags & 0x800000)
+ m_Flags |= kFormTextNoScroll;
+ if (flags & 0x100000)
+ m_Flags |= kFormTextComb;
+ }
+ LoadDA();
+ } else if (type_name == "Ch") {
+ if (flags & 0x20000) {
+ m_Type = ComboBox;
+ if (flags & 0x40000)
+ m_Flags |= kFormComboEdit;
+ } else {
+ m_Type = ListBox;
+ if (flags & 0x200000)
+ m_Flags |= kFormListMultiSelect;
+ }
+ LoadDA();
+ } else if (type_name == "Sig") {
+ m_Type = Sign;
+ }
+}
+
+CFX_WideString CPDF_FormField::GetFullName() const {
+ return FPDF_GetFullName(m_pDict);
+}
+
+FX_BOOL CPDF_FormField::ResetField(FX_BOOL bNotify) {
+ switch (m_Type) {
+ case CPDF_FormField::CheckBox:
+ case CPDF_FormField::RadioButton: {
+ int iCount = CountControls();
+ if (iCount) {
+ // TODO(weili): Check whether anything special needs to be done for
+ // unison field. Otherwise, merge these branches.
+ if (IsUnison(this)) {
+ for (int i = 0; i < iCount; i++)
+ CheckControl(i, GetControl(i)->IsDefaultChecked(), FALSE);
+ } else {
+ for (int i = 0; i < iCount; i++)
+ CheckControl(i, GetControl(i)->IsDefaultChecked(), FALSE);
+ }
+ }
+ if (bNotify && m_pForm->m_pFormNotify)
+ m_pForm->m_pFormNotify->AfterCheckedStatusChange(this);
+ break;
+ }
+ case CPDF_FormField::ComboBox:
+ case CPDF_FormField::ListBox: {
+ CFX_WideString csValue;
+ ClearSelection();
+ int iIndex = GetDefaultSelectedItem();
+ if (iIndex >= 0)
+ csValue = GetOptionLabel(iIndex);
+
+ if (bNotify && !NotifyListOrComboBoxBeforeChange(csValue))
+ return FALSE;
+
+ SetItemSelection(iIndex, TRUE);
+ if (bNotify)
+ NotifyListOrComboBoxAfterChange();
+ break;
+ }
+ case CPDF_FormField::Text:
+ case CPDF_FormField::RichText:
+ case CPDF_FormField::File:
+ default: {
+ CPDF_Object* pDV = FPDF_GetFieldAttr(m_pDict, "DV");
+ CFX_WideString csDValue;
+ if (pDV)
+ csDValue = pDV->GetUnicodeText();
+
+ CPDF_Object* pV = FPDF_GetFieldAttr(m_pDict, "V");
+ CFX_WideString csValue;
+ if (pV)
+ csValue = pV->GetUnicodeText();
+
+ CPDF_Object* pRV = FPDF_GetFieldAttr(m_pDict, "RV");
+ if (!pRV && (csDValue == csValue))
+ return FALSE;
+
+ if (bNotify && !NotifyBeforeValueChange(csDValue))
+ return FALSE;
+
+ if (pDV) {
+ CPDF_Object* pClone = pDV->Clone();
+ if (!pClone)
+ return FALSE;
+
+ m_pDict->SetAt("V", pClone);
+ if (pRV) {
+ CPDF_Object* pCloneR = pDV->Clone();
+ m_pDict->SetAt("RV", pCloneR);
+ }
+ } else {
+ m_pDict->RemoveAt("V");
+ m_pDict->RemoveAt("RV");
+ }
+ if (bNotify)
+ NotifyAfterValueChange();
+ break;
+ }
+ }
+ return TRUE;
+}
+
+int CPDF_FormField::GetControlIndex(const CPDF_FormControl* pControl) const {
+ if (!pControl)
+ return -1;
+
+ for (int i = 0; i < m_ControlList.GetSize(); i++) {
+ if (m_ControlList.GetAt(i) == pControl)
+ return i;
+ }
+ return -1;
+}
+
+int CPDF_FormField::GetFieldType() const {
+ switch (m_Type) {
+ case PushButton:
+ return FIELDTYPE_PUSHBUTTON;
+ case CheckBox:
+ return FIELDTYPE_CHECKBOX;
+ case RadioButton:
+ return FIELDTYPE_RADIOBUTTON;
+ case ComboBox:
+ return FIELDTYPE_COMBOBOX;
+ case ListBox:
+ return FIELDTYPE_LISTBOX;
+ case Text:
+ case RichText:
+ case File:
+ return FIELDTYPE_TEXTFIELD;
+ case Sign:
+ return FIELDTYPE_SIGNATURE;
+ default:
+ break;
+ }
+ return FIELDTYPE_UNKNOWN;
+}
+
+CPDF_AAction CPDF_FormField::GetAdditionalAction() const {
+ CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict, "AA");
+ return CPDF_AAction(pObj ? pObj->GetDict() : nullptr);
+}
+
+CFX_WideString CPDF_FormField::GetAlternateName() const {
+ CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict, "TU");
+ return pObj ? pObj->GetUnicodeText() : L"";
+}
+
+CFX_WideString CPDF_FormField::GetMappingName() const {
+ CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict, "TM");
+ return pObj ? pObj->GetUnicodeText() : L"";
+}
+
+uint32_t CPDF_FormField::GetFieldFlags() const {
+ CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict, "Ff");
+ return pObj ? pObj->GetInteger() : 0;
+}
+
+CFX_ByteString CPDF_FormField::GetDefaultStyle() const {
+ CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict, "DS");
+ return pObj ? pObj->GetString() : "";
+}
+
+CFX_WideString CPDF_FormField::GetRichTextString() const {
+ CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict, "RV");
+ return pObj ? pObj->GetUnicodeText() : L"";
+}
+
+CFX_WideString CPDF_FormField::GetValue(FX_BOOL bDefault) const {
+ if (GetType() == CheckBox || GetType() == RadioButton)
+ return GetCheckValue(bDefault);
+
+ CPDF_Object* pValue = FPDF_GetFieldAttr(m_pDict, bDefault ? "DV" : "V");
+ if (!pValue) {
+ if (!bDefault) {
+ if (m_Type == RichText)
+ pValue = FPDF_GetFieldAttr(m_pDict, "V");
+ if (!pValue && m_Type != Text)
+ pValue = FPDF_GetFieldAttr(m_pDict, "DV");
+ }
+ if (!pValue)
+ return CFX_WideString();
+ }
+
+ switch (pValue->GetType()) {
+ case CPDF_Object::STRING:
+ case CPDF_Object::STREAM:
+ return pValue->GetUnicodeText();
+ case CPDF_Object::ARRAY:
+ pValue = pValue->AsArray()->GetDirectObjectAt(0);
+ if (pValue)
+ return pValue->GetUnicodeText();
+ break;
+ default:
+ break;
+ }
+ return CFX_WideString();
+}
+
+CFX_WideString CPDF_FormField::GetValue() const {
+ return GetValue(FALSE);
+}
+
+CFX_WideString CPDF_FormField::GetDefaultValue() const {
+ return GetValue(TRUE);
+}
+
+FX_BOOL CPDF_FormField::SetValue(const CFX_WideString& value,
+ FX_BOOL bDefault,
+ FX_BOOL bNotify) {
+ switch (m_Type) {
+ case CheckBox:
+ case RadioButton: {
+ SetCheckValue(value, bDefault, bNotify);
+ return TRUE;
+ }
+ case File:
+ case RichText:
+ case Text:
+ case ComboBox: {
+ CFX_WideString csValue = value;
+ if (bNotify && !NotifyBeforeValueChange(csValue))
+ return FALSE;
+
+ int iIndex = FindOptionValue(csValue);
+ if (iIndex < 0) {
+ CFX_ByteString bsEncodeText = PDF_EncodeText(csValue);
+ m_pDict->SetAtString(bDefault ? "DV" : "V", bsEncodeText);
+ if (m_Type == RichText && !bDefault)
+ m_pDict->SetAtString("RV", bsEncodeText);
+ m_pDict->RemoveAt("I");
+ } else {
+ m_pDict->SetAtString(bDefault ? "DV" : "V", PDF_EncodeText(csValue));
+ if (!bDefault) {
+ ClearSelection();
+ SetItemSelection(iIndex, TRUE);
+ }
+ }
+ if (bNotify)
+ NotifyAfterValueChange();
+ break;
+ }
+ case ListBox: {
+ int iIndex = FindOptionValue(value);
+ if (iIndex < 0)
+ return FALSE;
+
+ if (bDefault && iIndex == GetDefaultSelectedItem())
+ return FALSE;
+
+ if (bNotify && !NotifyBeforeSelectionChange(value))
+ return FALSE;
+
+ if (!bDefault) {
+ ClearSelection();
+ SetItemSelection(iIndex, TRUE);
+ }
+ if (bNotify)
+ NotifyAfterSelectionChange();
+ break;
+ }
+ default:
+ break;
+ }
+ return TRUE;
+}
+
+FX_BOOL CPDF_FormField::SetValue(const CFX_WideString& value, FX_BOOL bNotify) {
+ return SetValue(value, FALSE, bNotify);
+}
+
+int CPDF_FormField::GetMaxLen() const {
+ if (CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict, "MaxLen"))
+ return pObj->GetInteger();
+
+ for (int i = 0; i < m_ControlList.GetSize(); i++) {
+ CPDF_FormControl* pControl = m_ControlList.GetAt(i);
+ if (!pControl)
+ continue;
+
+ CPDF_Dictionary* pWidgetDict = pControl->m_pWidgetDict;
+ if (pWidgetDict->KeyExist("MaxLen"))
+ return pWidgetDict->GetIntegerBy("MaxLen");
+ }
+ return 0;
+}
+
+int CPDF_FormField::CountSelectedItems() const {
+ CPDF_Object* pValue = FPDF_GetFieldAttr(m_pDict, "V");
+ if (!pValue) {
+ pValue = FPDF_GetFieldAttr(m_pDict, "I");
+ if (!pValue)
+ return 0;
+ }
+
+ if (pValue->IsString() || pValue->IsNumber())
+ return pValue->GetString().IsEmpty() ? 0 : 1;
+ if (CPDF_Array* pArray = pValue->AsArray())
+ return pArray->GetCount();
+ return 0;
+}
+
+int CPDF_FormField::GetSelectedIndex(int index) const {
+ CPDF_Object* pValue = FPDF_GetFieldAttr(m_pDict, "V");
+ if (!pValue) {
+ pValue = FPDF_GetFieldAttr(m_pDict, "I");
+ if (!pValue)
+ return -1;
+ }
+ if (pValue->IsNumber())
+ return pValue->GetInteger();
+
+ CFX_WideString sel_value;
+ if (pValue->IsString()) {
+ if (index != 0)
+ return -1;
+ sel_value = pValue->GetUnicodeText();
+ } else {
+ CPDF_Array* pArray = pValue->AsArray();
+ if (!pArray || index < 0)
+ return -1;
+
+ CPDF_Object* elementValue = pArray->GetDirectObjectAt(index);
+ sel_value =
+ elementValue ? elementValue->GetUnicodeText() : CFX_WideString();
+ }
+ if (index < CountSelectedOptions()) {
+ int iOptIndex = GetSelectedOptionIndex(index);
+ CFX_WideString csOpt = GetOptionValue(iOptIndex);
+ if (csOpt == sel_value)
+ return iOptIndex;
+ }
+ for (int i = 0; i < CountOptions(); i++) {
+ if (sel_value == GetOptionValue(i))
+ return i;
+ }
+ return -1;
+}
+
+FX_BOOL CPDF_FormField::ClearSelection(FX_BOOL bNotify) {
+ if (bNotify && m_pForm->m_pFormNotify) {
+ CFX_WideString csValue;
+ int iIndex = GetSelectedIndex(0);
+ if (iIndex >= 0)
+ csValue = GetOptionLabel(iIndex);
+
+ if (!NotifyListOrComboBoxBeforeChange(csValue))
+ return FALSE;
+ }
+ m_pDict->RemoveAt("V");
+ m_pDict->RemoveAt("I");
+ if (bNotify)
+ NotifyListOrComboBoxAfterChange();
+ return TRUE;
+}
+
+FX_BOOL CPDF_FormField::IsItemSelected(int index) const {
+ ASSERT(GetType() == ComboBox || GetType() == ListBox);
+ if (index < 0 || index >= CountOptions())
+ return FALSE;
+ if (IsOptionSelected(index))
+ return TRUE;
+
+ CFX_WideString opt_value = GetOptionValue(index);
+ CPDF_Object* pValue = FPDF_GetFieldAttr(m_pDict, "V");
+ if (!pValue) {
+ pValue = FPDF_GetFieldAttr(m_pDict, "I");
+ if (!pValue)
+ return FALSE;
+ }
+
+ if (pValue->IsString())
+ return pValue->GetUnicodeText() == opt_value;
+
+ if (pValue->IsNumber()) {
+ if (pValue->GetString().IsEmpty())
+ return FALSE;
+ return (pValue->GetInteger() == index);
+ }
+
+ CPDF_Array* pArray = pValue->AsArray();
+ if (!pArray)
+ return FALSE;
+
+ int iPos = -1;
+ for (int j = 0; j < CountSelectedOptions(); j++) {
+ if (GetSelectedOptionIndex(j) == index) {
+ iPos = j;
+ break;
+ }
+ }
+ for (int i = 0; i < static_cast<int>(pArray->GetCount()); i++)
+ if (pArray->GetDirectObjectAt(i)->GetUnicodeText() == opt_value &&
+ i == iPos) {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+FX_BOOL CPDF_FormField::SetItemSelection(int index,
+ FX_BOOL bSelected,
+ FX_BOOL bNotify) {
+ ASSERT(GetType() == ComboBox || GetType() == ListBox);
+ if (index < 0 || index >= CountOptions())
+ return FALSE;
+
+ CFX_WideString opt_value = GetOptionValue(index);
+ if (bNotify && !NotifyListOrComboBoxBeforeChange(opt_value))
+ return FALSE;
+
+ if (bSelected) {
+ if (GetType() == ListBox) {
+ SelectOption(index, TRUE);
+ if (!(m_Flags & kFormListMultiSelect)) {
+ m_pDict->SetAtString("V", PDF_EncodeText(opt_value));
+ } else {
+ CPDF_Array* pArray = new CPDF_Array;
+ for (int i = 0; i < CountOptions(); i++) {
+ if (i == index || IsItemSelected(i)) {
+ opt_value = GetOptionValue(i);
+ pArray->AddString(PDF_EncodeText(opt_value));
+ }
+ }
+ m_pDict->SetAt("V", pArray);
+ }
+ } else {
+ m_pDict->SetAtString("V", PDF_EncodeText(opt_value));
+ CPDF_Array* pI = new CPDF_Array;
+ pI->AddInteger(index);
+ m_pDict->SetAt("I", pI);
+ }
+ } else {
+ CPDF_Object* pValue = FPDF_GetFieldAttr(m_pDict, "V");
+ if (pValue) {
+ if (GetType() == ListBox) {
+ SelectOption(index, FALSE);
+ if (pValue->IsString()) {
+ if (pValue->GetUnicodeText() == opt_value)
+ m_pDict->RemoveAt("V");
+ } else if (pValue->IsArray()) {
+ CPDF_Array* pArray = new CPDF_Array;
+ for (int i = 0; i < CountOptions(); i++) {
+ if (i != index && IsItemSelected(i)) {
+ opt_value = GetOptionValue(i);
+ pArray->AddString(PDF_EncodeText(opt_value));
+ }
+ }
+ if (pArray->GetCount() < 1)
+ pArray->Release();
+ else
+ m_pDict->SetAt("V", pArray);
+ }
+ } else {
+ m_pDict->RemoveAt("V");
+ m_pDict->RemoveAt("I");
+ }
+ }
+ }
+ if (bNotify)
+ NotifyListOrComboBoxAfterChange();
+ return TRUE;
+}
+
+FX_BOOL CPDF_FormField::IsItemDefaultSelected(int index) const {
+ ASSERT(GetType() == ComboBox || GetType() == ListBox);
+ if (index < 0 || index >= CountOptions())
+ return FALSE;
+ int iDVIndex = GetDefaultSelectedItem();
+ return iDVIndex >= 0 && iDVIndex == index;
+}
+
+int CPDF_FormField::GetDefaultSelectedItem() const {
+ ASSERT(GetType() == ComboBox || GetType() == ListBox);
+ CPDF_Object* pValue = FPDF_GetFieldAttr(m_pDict, "DV");
+ if (!pValue)
+ return -1;
+ CFX_WideString csDV = pValue->GetUnicodeText();
+ if (csDV.IsEmpty())
+ return -1;
+ for (int i = 0; i < CountOptions(); i++) {
+ if (csDV == GetOptionValue(i))
+ return i;
+ }
+ return -1;
+}
+
+int CPDF_FormField::CountOptions() const {
+ CPDF_Array* pArray = ToArray(FPDF_GetFieldAttr(m_pDict, "Opt"));
+ return pArray ? pArray->GetCount() : 0;
+}
+
+CFX_WideString CPDF_FormField::GetOptionText(int index, int sub_index) const {
+ CPDF_Array* pArray = ToArray(FPDF_GetFieldAttr(m_pDict, "Opt"));
+ if (!pArray)
+ return CFX_WideString();
+
+ CPDF_Object* pOption = pArray->GetDirectObjectAt(index);
+ if (!pOption)
+ return CFX_WideString();
+ if (CPDF_Array* pOptionArray = pOption->AsArray())
+ pOption = pOptionArray->GetDirectObjectAt(sub_index);
+
+ CPDF_String* pString = ToString(pOption);
+ return pString ? pString->GetUnicodeText() : CFX_WideString();
+}
+
+CFX_WideString CPDF_FormField::GetOptionLabel(int index) const {
+ return GetOptionText(index, 1);
+}
+
+CFX_WideString CPDF_FormField::GetOptionValue(int index) const {
+ return GetOptionText(index, 0);
+}
+
+int CPDF_FormField::FindOption(CFX_WideString csOptLabel) const {
+ for (int i = 0; i < CountOptions(); i++) {
+ if (GetOptionValue(i) == csOptLabel)
+ return i;
+ }
+ return -1;
+}
+
+int CPDF_FormField::FindOptionValue(const CFX_WideString& csOptValue) const {
+ for (int i = 0; i < CountOptions(); i++) {
+ if (GetOptionValue(i) == csOptValue)
+ return i;
+ }
+ return -1;
+}
+
+#ifdef PDF_ENABLE_XFA
+int CPDF_FormField::InsertOption(CFX_WideString csOptLabel,
+ int index,
+ FX_BOOL bNotify) {
+ if (csOptLabel.IsEmpty())
+ return -1;
+
+ if (bNotify && !NotifyListOrComboBoxBeforeChange(csOptLabel))
+ return -1;
+
+ CFX_ByteString csStr =
+ PDF_EncodeText(csOptLabel.c_str(), csOptLabel.GetLength());
+ CPDF_Object* pValue = FPDF_GetFieldAttr(m_pDict, "Opt");
+ CPDF_Array* pOpt = ToArray(pValue);
+ if (!pOpt) {
+ pOpt = new CPDF_Array;
+ m_pDict->SetAt("Opt", pOpt);
+ }
+
+ int iCount = (int)pOpt->GetCount();
+ if (index < 0 || index >= iCount) {
+ pOpt->AddString(csStr);
+ index = iCount;
+ } else {
+ CPDF_String* pString = new CPDF_String(csStr, FALSE);
+ pOpt->InsertAt(index, pString);
+ }
+
+ if (bNotify)
+ NotifyListOrComboBoxAfterChange();
+ return index;
+}
+
+FX_BOOL CPDF_FormField::ClearOptions(FX_BOOL bNotify) {
+ if (bNotify && m_pForm->m_pFormNotify) {
+ CFX_WideString csValue;
+ int iIndex = GetSelectedIndex(0);
+ if (iIndex >= 0)
+ csValue = GetOptionLabel(iIndex);
+ if (!NotifyListOrComboBoxBeforeChange(csValue))
+ return FALSE;
+ }
+
+ m_pDict->RemoveAt("Opt");
+ m_pDict->RemoveAt("V");
+ m_pDict->RemoveAt("DV");
+ m_pDict->RemoveAt("I");
+ m_pDict->RemoveAt("TI");
+
+ if (bNotify)
+ NotifyListOrComboBoxAfterChange();
+
+ return TRUE;
+}
+#endif // PDF_ENABLE_XFA
+
+FX_BOOL CPDF_FormField::CheckControl(int iControlIndex,
+ bool bChecked,
+ bool bNotify) {
+ ASSERT(GetType() == CheckBox || GetType() == RadioButton);
+ CPDF_FormControl* pControl = GetControl(iControlIndex);
+ if (!pControl)
+ return FALSE;
+ if (!bChecked && pControl->IsChecked() == bChecked)
+ return FALSE;
+
+ CFX_WideString csWExport = pControl->GetExportValue();
+ CFX_ByteString csBExport = PDF_EncodeText(csWExport);
+ int iCount = CountControls();
+ bool bUnison = IsUnison(this);
+ for (int i = 0; i < iCount; i++) {
+ CPDF_FormControl* pCtrl = GetControl(i);
+ if (bUnison) {
+ CFX_WideString csEValue = pCtrl->GetExportValue();
+ if (csEValue == csWExport) {
+ if (pCtrl->GetOnStateName() == pControl->GetOnStateName())
+ pCtrl->CheckControl(bChecked);
+ else if (bChecked)
+ pCtrl->CheckControl(FALSE);
+ } else if (bChecked) {
+ pCtrl->CheckControl(FALSE);
+ }
+ } else {
+ if (i == iControlIndex)
+ pCtrl->CheckControl(bChecked);
+ else if (bChecked)
+ pCtrl->CheckControl(FALSE);
+ }
+ }
+
+ CPDF_Object* pOpt = FPDF_GetFieldAttr(m_pDict, "Opt");
+ if (!ToArray(pOpt)) {
+ if (bChecked) {
+ m_pDict->SetAtName("V", csBExport);
+ } else {
+ CFX_ByteString csV;
+ CPDF_Object* pV = FPDF_GetFieldAttr(m_pDict, "V");
+ if (pV)
+ csV = pV->GetString();
+ if (csV == csBExport)
+ m_pDict->SetAtName("V", "Off");
+ }
+ } else if (bChecked) {
+ CFX_ByteString csIndex;
+ csIndex.Format("%d", iControlIndex);
+ m_pDict->SetAtName("V", csIndex);
+ }
+ if (bNotify && m_pForm->m_pFormNotify)
+ m_pForm->m_pFormNotify->AfterCheckedStatusChange(this);
+ return TRUE;
+}
+
+CFX_WideString CPDF_FormField::GetCheckValue(FX_BOOL bDefault) const {
+ ASSERT(GetType() == CheckBox || GetType() == RadioButton);
+ CFX_WideString csExport = L"Off";
+ int iCount = CountControls();
+ for (int i = 0; i < iCount; i++) {
+ CPDF_FormControl* pControl = GetControl(i);
+ FX_BOOL bChecked =
+ bDefault ? pControl->IsDefaultChecked() : pControl->IsChecked();
+ if (bChecked) {
+ csExport = pControl->GetExportValue();
+ break;
+ }
+ }
+ return csExport;
+}
+
+FX_BOOL CPDF_FormField::SetCheckValue(const CFX_WideString& value,
+ FX_BOOL bDefault,
+ FX_BOOL bNotify) {
+ ASSERT(GetType() == CheckBox || GetType() == RadioButton);
+ int iCount = CountControls();
+ for (int i = 0; i < iCount; i++) {
+ CPDF_FormControl* pControl = GetControl(i);
+ CFX_WideString csExport = pControl->GetExportValue();
+ bool val = csExport == value;
+ if (!bDefault)
+ CheckControl(GetControlIndex(pControl), val);
+ if (val)
+ break;
+ }
+ if (bNotify && m_pForm->m_pFormNotify)
+ m_pForm->m_pFormNotify->AfterCheckedStatusChange(this);
+ return TRUE;
+}
+
+int CPDF_FormField::GetTopVisibleIndex() const {
+ CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict, "TI");
+ return pObj ? pObj->GetInteger() : 0;
+}
+
+int CPDF_FormField::CountSelectedOptions() const {
+ CPDF_Array* pArray = ToArray(FPDF_GetFieldAttr(m_pDict, "I"));
+ return pArray ? pArray->GetCount() : 0;
+}
+
+int CPDF_FormField::GetSelectedOptionIndex(int index) const {
+ CPDF_Array* pArray = ToArray(FPDF_GetFieldAttr(m_pDict, "I"));
+ if (!pArray)
+ return -1;
+
+ int iCount = pArray->GetCount();
+ if (iCount < 0 || index >= iCount)
+ return -1;
+ return pArray->GetIntegerAt(index);
+}
+
+FX_BOOL CPDF_FormField::IsOptionSelected(int iOptIndex) const {
+ CPDF_Array* pArray = ToArray(FPDF_GetFieldAttr(m_pDict, "I"));
+ if (!pArray)
+ return FALSE;
+
+ for (CPDF_Object* pObj : *pArray) {
+ if (pObj->GetInteger() == iOptIndex)
+ return TRUE;
+ }
+ return FALSE;
+}
+
+FX_BOOL CPDF_FormField::SelectOption(int iOptIndex,
+ FX_BOOL bSelected,
+ FX_BOOL bNotify) {
+ CPDF_Array* pArray = m_pDict->GetArrayBy("I");
+ if (!pArray) {
+ if (!bSelected)
+ return TRUE;
+
+ pArray = new CPDF_Array;
+ m_pDict->SetAt("I", pArray);
+ }
+
+ FX_BOOL bReturn = FALSE;
+ for (size_t i = 0; i < pArray->GetCount(); i++) {
+ int iFind = pArray->GetIntegerAt(i);
+ if (iFind == iOptIndex) {
+ if (bSelected)
+ return TRUE;
+
+ if (bNotify && m_pForm->m_pFormNotify) {
+ CFX_WideString csValue = GetOptionLabel(iOptIndex);
+ if (!NotifyListOrComboBoxBeforeChange(csValue))
+ return FALSE;
+ }
+ pArray->RemoveAt(i);
+ bReturn = TRUE;
+ break;
+ }
+
+ if (iFind > iOptIndex) {
+ if (!bSelected)
+ continue;
+
+ if (bNotify && m_pForm->m_pFormNotify) {
+ CFX_WideString csValue = GetOptionLabel(iOptIndex);
+ if (!NotifyListOrComboBoxBeforeChange(csValue))
+ return FALSE;
+ }
+ pArray->InsertAt(i, new CPDF_Number(iOptIndex));
+ bReturn = TRUE;
+ break;
+ }
+ }
+ if (!bReturn) {
+ if (bSelected)
+ pArray->AddInteger(iOptIndex);
+
+ if (pArray->GetCount() == 0)
+ m_pDict->RemoveAt("I");
+ }
+ if (bNotify)
+ NotifyListOrComboBoxAfterChange();
+
+ return TRUE;
+}
+
+FX_BOOL CPDF_FormField::ClearSelectedOptions(FX_BOOL bNotify) {
+ if (bNotify && m_pForm->m_pFormNotify) {
+ CFX_WideString csValue;
+ int iIndex = GetSelectedIndex(0);
+ if (iIndex >= 0)
+ csValue = GetOptionLabel(iIndex);
+
+ if (!NotifyListOrComboBoxBeforeChange(csValue))
+ return FALSE;
+ }
+ m_pDict->RemoveAt("I");
+ if (bNotify)
+ NotifyListOrComboBoxAfterChange();
+
+ return TRUE;
+}
+
+void CPDF_FormField::LoadDA() {
+ CPDF_Dictionary* pFormDict = m_pForm->m_pFormDict;
+ if (!pFormDict)
+ return;
+
+ CFX_ByteString DA;
+ if (CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict, "DA"))
+ DA = pObj->GetString();
+
+ if (DA.IsEmpty())
+ DA = pFormDict->GetStringBy("DA");
+
+ if (DA.IsEmpty())
+ return;
+
+ CPDF_Dictionary* pDR = pFormDict->GetDictBy("DR");
+ if (!pDR)
+ return;
+
+ CPDF_Dictionary* pFont = pDR->GetDictBy("Font");
+ if (!pFont)
+ return;
+
+ CPDF_SimpleParser syntax(DA.AsStringC());
+ syntax.FindTagParamFromStart("Tf", 2);
+ CFX_ByteString font_name(syntax.GetWord());
+ CPDF_Dictionary* pFontDict = pFont->GetDictBy(font_name);
+ if (!pFontDict)
+ return;
+
+ m_pFont = m_pForm->m_pDocument->LoadFont(pFontDict);
+ m_FontSize = FX_atof(syntax.GetWord());
+}
+
+bool CPDF_FormField::NotifyBeforeSelectionChange(const CFX_WideString& value) {
+ if (!m_pForm->m_pFormNotify)
+ return true;
+ return m_pForm->m_pFormNotify->BeforeSelectionChange(this, value) >= 0;
+}
+
+void CPDF_FormField::NotifyAfterSelectionChange() {
+ if (!m_pForm->m_pFormNotify)
+ return;
+ m_pForm->m_pFormNotify->AfterSelectionChange(this);
+}
+
+bool CPDF_FormField::NotifyBeforeValueChange(const CFX_WideString& value) {
+ if (!m_pForm->m_pFormNotify)
+ return true;
+ return m_pForm->m_pFormNotify->BeforeValueChange(this, value) >= 0;
+}
+
+void CPDF_FormField::NotifyAfterValueChange() {
+ if (!m_pForm->m_pFormNotify)
+ return;
+ m_pForm->m_pFormNotify->AfterValueChange(this);
+}
+
+bool CPDF_FormField::NotifyListOrComboBoxBeforeChange(
+ const CFX_WideString& value) {
+ switch (GetType()) {
+ case ListBox:
+ return NotifyBeforeSelectionChange(value);
+ case ComboBox:
+ return NotifyBeforeValueChange(value);
+ default:
+ return true;
+ }
+}
+
+void CPDF_FormField::NotifyListOrComboBoxAfterChange() {
+ switch (GetType()) {
+ case ListBox:
+ NotifyAfterSelectionChange();
+ break;
+ case ComboBox:
+ NotifyAfterValueChange();
+ break;
+ default:
+ break;
+ }
+}