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/fpdfdoc/cpdf_formfield.h" 8 9 #include <memory> 10 #include <set> 11 #include <utility> 12 13 #include "core/fpdfapi/parser/cfdf_document.h" 14 #include "core/fpdfapi/parser/cpdf_array.h" 15 #include "core/fpdfapi/parser/cpdf_document.h" 16 #include "core/fpdfapi/parser/cpdf_name.h" 17 #include "core/fpdfapi/parser/cpdf_number.h" 18 #include "core/fpdfapi/parser/cpdf_simple_parser.h" 19 #include "core/fpdfapi/parser/cpdf_string.h" 20 #include "core/fpdfapi/parser/fpdf_parser_decode.h" 21 #include "core/fpdfdoc/cpdf_formcontrol.h" 22 #include "core/fpdfdoc/cpdf_interform.h" 23 #include "core/fpdfdoc/cpvt_generateap.h" 24 #include "third_party/base/stl_util.h" 25 26 namespace { 27 28 const int kFormListMultiSelect = 0x100; 29 30 const int kFormComboEdit = 0x100; 31 32 const int kFormRadioNoToggleOff = 0x100; 33 const int kFormRadioUnison = 0x200; 34 35 const int kFormTextMultiLine = 0x100; 36 const int kFormTextPassword = 0x200; 37 const int kFormTextNoScroll = 0x400; 38 const int kFormTextComb = 0x800; 39 40 bool IsUnison(CPDF_FormField* pField) { 41 if (pField->GetType() == CPDF_FormField::CheckBox) 42 return true; 43 return (pField->GetFieldFlags() & 0x2000000) != 0; 44 } 45 46 } // namespace 47 48 Optional<FormFieldType> IntToFormFieldType(int value) { 49 if (value >= static_cast<int>(FormFieldType::kUnknown) && 50 value < static_cast<int>(kFormFieldTypeCount)) { 51 return {static_cast<FormFieldType>(value)}; 52 } 53 return {}; 54 } 55 56 CPDF_Object* FPDF_GetFieldAttr(const CPDF_Dictionary* pFieldDict, 57 const char* name, 58 int nLevel) { 59 static constexpr int kGetFieldMaxRecursion = 32; 60 if (!pFieldDict || nLevel > kGetFieldMaxRecursion) 61 return nullptr; 62 63 CPDF_Object* pAttr = pFieldDict->GetDirectObjectFor(name); 64 if (pAttr) 65 return pAttr; 66 67 CPDF_Dictionary* pParent = pFieldDict->GetDictFor("Parent"); 68 return pParent ? FPDF_GetFieldAttr(pParent, name, nLevel + 1) : nullptr; 69 } 70 71 WideString FPDF_GetFullName(CPDF_Dictionary* pFieldDict) { 72 WideString full_name; 73 std::set<CPDF_Dictionary*> visited; 74 CPDF_Dictionary* pLevel = pFieldDict; 75 while (pLevel) { 76 visited.insert(pLevel); 77 WideString short_name = pLevel->GetUnicodeTextFor("T"); 78 if (!short_name.IsEmpty()) { 79 if (full_name.IsEmpty()) 80 full_name = short_name; 81 else 82 full_name = short_name + L"." + full_name; 83 } 84 pLevel = pLevel->GetDictFor("Parent"); 85 if (pdfium::ContainsKey(visited, pLevel)) 86 break; 87 } 88 return full_name; 89 } 90 91 CPDF_FormField::CPDF_FormField(CPDF_InterForm* pForm, CPDF_Dictionary* pDict) 92 : m_Type(Unknown), 93 m_pForm(pForm), 94 m_pDict(pDict), 95 m_FontSize(0), 96 m_pFont(nullptr) { 97 SyncFieldFlags(); 98 } 99 100 CPDF_FormField::~CPDF_FormField() {} 101 102 void CPDF_FormField::SyncFieldFlags() { 103 CPDF_Object* ft_attr = FPDF_GetFieldAttr(m_pDict.Get(), "FT"); 104 ByteString type_name = ft_attr ? ft_attr->GetString() : ByteString(); 105 CPDF_Object* ff_attr = FPDF_GetFieldAttr(m_pDict.Get(), "Ff"); 106 uint32_t flags = ff_attr ? ff_attr->GetInteger() : 0; 107 m_Flags = 0; 108 if (flags & FORMFLAG_READONLY) 109 m_Flags |= FORMFLAG_READONLY; 110 if (flags & FORMFLAG_REQUIRED) 111 m_Flags |= FORMFLAG_REQUIRED; 112 if (flags & FORMFLAG_NOEXPORT) 113 m_Flags |= FORMFLAG_NOEXPORT; 114 115 if (type_name == "Btn") { 116 if (flags & 0x8000) { 117 m_Type = RadioButton; 118 if (flags & 0x4000) 119 m_Flags |= kFormRadioNoToggleOff; 120 if (flags & 0x2000000) 121 m_Flags |= kFormRadioUnison; 122 } else if (flags & 0x10000) { 123 m_Type = PushButton; 124 } else { 125 m_Type = CheckBox; 126 } 127 } else if (type_name == "Tx") { 128 if (flags & 0x100000) { 129 m_Type = File; 130 } else if (flags & 0x2000000) { 131 m_Type = RichText; 132 } else { 133 m_Type = Text; 134 if (flags & 0x1000) 135 m_Flags |= kFormTextMultiLine; 136 if (flags & 0x2000) 137 m_Flags |= kFormTextPassword; 138 if (flags & 0x800000) 139 m_Flags |= kFormTextNoScroll; 140 if (flags & 0x100000) 141 m_Flags |= kFormTextComb; 142 } 143 LoadDA(); 144 } else if (type_name == "Ch") { 145 if (flags & 0x20000) { 146 m_Type = ComboBox; 147 if (flags & 0x40000) 148 m_Flags |= kFormComboEdit; 149 } else { 150 m_Type = ListBox; 151 if (flags & 0x200000) 152 m_Flags |= kFormListMultiSelect; 153 } 154 LoadDA(); 155 } else if (type_name == "Sig") { 156 m_Type = Sign; 157 } 158 } 159 160 WideString CPDF_FormField::GetFullName() const { 161 return FPDF_GetFullName(m_pDict.Get()); 162 } 163 164 bool CPDF_FormField::ResetField(bool bNotify) { 165 switch (m_Type) { 166 case CPDF_FormField::CheckBox: 167 case CPDF_FormField::RadioButton: { 168 int iCount = CountControls(); 169 if (iCount) { 170 // TODO(weili): Check whether anything special needs to be done for 171 // unison field. Otherwise, merge these branches. 172 if (IsUnison(this)) { 173 for (int i = 0; i < iCount; i++) 174 CheckControl(i, GetControl(i)->IsDefaultChecked(), false); 175 } else { 176 for (int i = 0; i < iCount; i++) 177 CheckControl(i, GetControl(i)->IsDefaultChecked(), false); 178 } 179 } 180 if (bNotify && m_pForm->GetFormNotify()) 181 m_pForm->GetFormNotify()->AfterCheckedStatusChange(this); 182 break; 183 } 184 case CPDF_FormField::ComboBox: 185 case CPDF_FormField::ListBox: { 186 WideString csValue; 187 ClearSelection(); 188 int iIndex = GetDefaultSelectedItem(); 189 if (iIndex >= 0) 190 csValue = GetOptionLabel(iIndex); 191 192 if (bNotify && !NotifyListOrComboBoxBeforeChange(csValue)) 193 return false; 194 195 SetItemSelection(iIndex, true); 196 if (bNotify) 197 NotifyListOrComboBoxAfterChange(); 198 break; 199 } 200 case CPDF_FormField::Text: 201 case CPDF_FormField::RichText: 202 case CPDF_FormField::File: 203 default: { 204 CPDF_Object* pDV = FPDF_GetFieldAttr(m_pDict.Get(), "DV"); 205 WideString csDValue; 206 if (pDV) 207 csDValue = pDV->GetUnicodeText(); 208 209 CPDF_Object* pV = FPDF_GetFieldAttr(m_pDict.Get(), "V"); 210 WideString csValue; 211 if (pV) 212 csValue = pV->GetUnicodeText(); 213 214 CPDF_Object* pRV = FPDF_GetFieldAttr(m_pDict.Get(), "RV"); 215 if (!pRV && (csDValue == csValue)) 216 return false; 217 218 if (bNotify && !NotifyBeforeValueChange(csDValue)) 219 return false; 220 221 if (pDV) { 222 std::unique_ptr<CPDF_Object> pClone = pDV->Clone(); 223 if (!pClone) 224 return false; 225 226 m_pDict->SetFor("V", std::move(pClone)); 227 if (pRV) 228 m_pDict->SetFor("RV", pDV->Clone()); 229 } else { 230 m_pDict->RemoveFor("V"); 231 m_pDict->RemoveFor("RV"); 232 } 233 if (bNotify) 234 NotifyAfterValueChange(); 235 break; 236 } 237 } 238 return true; 239 } 240 241 int CPDF_FormField::GetControlIndex(const CPDF_FormControl* pControl) const { 242 if (!pControl) 243 return -1; 244 245 auto it = std::find(m_ControlList.begin(), m_ControlList.end(), pControl); 246 return it != m_ControlList.end() ? it - m_ControlList.begin() : -1; 247 } 248 249 FormFieldType CPDF_FormField::GetFieldType() const { 250 switch (m_Type) { 251 case PushButton: 252 return FormFieldType::kPushButton; 253 case CheckBox: 254 return FormFieldType::kCheckBox; 255 case RadioButton: 256 return FormFieldType::kRadioButton; 257 case ComboBox: 258 return FormFieldType::kComboBox; 259 case ListBox: 260 return FormFieldType::kListBox; 261 case Text: 262 case RichText: 263 case File: 264 return FormFieldType::kTextField; 265 case Sign: 266 return FormFieldType::kSignature; 267 default: 268 return FormFieldType::kUnknown; 269 } 270 } 271 272 CPDF_AAction CPDF_FormField::GetAdditionalAction() const { 273 CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict.Get(), "AA"); 274 return CPDF_AAction(pObj ? pObj->GetDict() : nullptr); 275 } 276 277 WideString CPDF_FormField::GetAlternateName() const { 278 CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict.Get(), "TU"); 279 return pObj ? pObj->GetUnicodeText() : L""; 280 } 281 282 WideString CPDF_FormField::GetMappingName() const { 283 CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict.Get(), "TM"); 284 return pObj ? pObj->GetUnicodeText() : L""; 285 } 286 287 uint32_t CPDF_FormField::GetFieldFlags() const { 288 CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict.Get(), "Ff"); 289 return pObj ? pObj->GetInteger() : 0; 290 } 291 292 ByteString CPDF_FormField::GetDefaultStyle() const { 293 CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict.Get(), "DS"); 294 return pObj ? pObj->GetString() : ""; 295 } 296 297 WideString CPDF_FormField::GetRichTextString() const { 298 CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict.Get(), "RV"); 299 return pObj ? pObj->GetUnicodeText() : L""; 300 } 301 302 WideString CPDF_FormField::GetValue(bool bDefault) const { 303 if (GetType() == CheckBox || GetType() == RadioButton) 304 return GetCheckValue(bDefault); 305 306 CPDF_Object* pValue = FPDF_GetFieldAttr(m_pDict.Get(), bDefault ? "DV" : "V"); 307 if (!pValue) { 308 if (!bDefault) { 309 if (m_Type == RichText) 310 pValue = FPDF_GetFieldAttr(m_pDict.Get(), "V"); 311 if (!pValue && m_Type != Text) 312 pValue = FPDF_GetFieldAttr(m_pDict.Get(), "DV"); 313 } 314 if (!pValue) 315 return WideString(); 316 } 317 318 switch (pValue->GetType()) { 319 case CPDF_Object::STRING: 320 case CPDF_Object::STREAM: 321 return pValue->GetUnicodeText(); 322 case CPDF_Object::ARRAY: 323 pValue = pValue->AsArray()->GetDirectObjectAt(0); 324 if (pValue) 325 return pValue->GetUnicodeText(); 326 break; 327 default: 328 break; 329 } 330 return WideString(); 331 } 332 333 WideString CPDF_FormField::GetValue() const { 334 return GetValue(false); 335 } 336 337 WideString CPDF_FormField::GetDefaultValue() const { 338 return GetValue(true); 339 } 340 341 bool CPDF_FormField::SetValue(const WideString& value, 342 bool bDefault, 343 bool bNotify) { 344 switch (m_Type) { 345 case CheckBox: 346 case RadioButton: { 347 SetCheckValue(value, bDefault, bNotify); 348 return true; 349 } 350 case File: 351 case RichText: 352 case Text: 353 case ComboBox: { 354 WideString csValue = value; 355 if (bNotify && !NotifyBeforeValueChange(csValue)) 356 return false; 357 358 ByteString key(bDefault ? "DV" : "V"); 359 int iIndex = FindOptionValue(csValue); 360 if (iIndex < 0) { 361 ByteString bsEncodeText = PDF_EncodeText(csValue); 362 m_pDict->SetNewFor<CPDF_String>(key, bsEncodeText, false); 363 if (m_Type == RichText && !bDefault) 364 m_pDict->SetNewFor<CPDF_String>("RV", bsEncodeText, false); 365 m_pDict->RemoveFor("I"); 366 } else { 367 m_pDict->SetNewFor<CPDF_String>(key, PDF_EncodeText(csValue), false); 368 if (!bDefault) { 369 ClearSelection(); 370 SetItemSelection(iIndex, true); 371 } 372 } 373 if (bNotify) 374 NotifyAfterValueChange(); 375 break; 376 } 377 case ListBox: { 378 int iIndex = FindOptionValue(value); 379 if (iIndex < 0) 380 return false; 381 382 if (bDefault && iIndex == GetDefaultSelectedItem()) 383 return false; 384 385 if (bNotify && !NotifyBeforeSelectionChange(value)) 386 return false; 387 388 if (!bDefault) { 389 ClearSelection(); 390 SetItemSelection(iIndex, true); 391 } 392 if (bNotify) 393 NotifyAfterSelectionChange(); 394 break; 395 } 396 default: 397 break; 398 } 399 return true; 400 } 401 402 bool CPDF_FormField::SetValue(const WideString& value, bool bNotify) { 403 return SetValue(value, false, bNotify); 404 } 405 406 int CPDF_FormField::GetMaxLen() const { 407 if (CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict.Get(), "MaxLen")) 408 return pObj->GetInteger(); 409 410 for (auto& pControl : m_ControlList) { 411 if (!pControl) 412 continue; 413 CPDF_Dictionary* pWidgetDict = pControl->GetWidget(); 414 if (pWidgetDict->KeyExist("MaxLen")) 415 return pWidgetDict->GetIntegerFor("MaxLen"); 416 } 417 return 0; 418 } 419 420 int CPDF_FormField::CountSelectedItems() const { 421 CPDF_Object* pValue = FPDF_GetFieldAttr(m_pDict.Get(), "V"); 422 if (!pValue) { 423 pValue = FPDF_GetFieldAttr(m_pDict.Get(), "I"); 424 if (!pValue) 425 return 0; 426 } 427 428 if (pValue->IsString() || pValue->IsNumber()) 429 return pValue->GetString().IsEmpty() ? 0 : 1; 430 if (CPDF_Array* pArray = pValue->AsArray()) 431 return pArray->GetCount(); 432 return 0; 433 } 434 435 int CPDF_FormField::GetSelectedIndex(int index) const { 436 CPDF_Object* pValue = FPDF_GetFieldAttr(m_pDict.Get(), "V"); 437 if (!pValue) { 438 pValue = FPDF_GetFieldAttr(m_pDict.Get(), "I"); 439 if (!pValue) 440 return -1; 441 } 442 if (pValue->IsNumber()) 443 return pValue->GetInteger(); 444 445 WideString sel_value; 446 if (pValue->IsString()) { 447 if (index != 0) 448 return -1; 449 sel_value = pValue->GetUnicodeText(); 450 } else { 451 CPDF_Array* pArray = pValue->AsArray(); 452 if (!pArray || index < 0) 453 return -1; 454 455 CPDF_Object* elementValue = pArray->GetDirectObjectAt(index); 456 sel_value = elementValue ? elementValue->GetUnicodeText() : WideString(); 457 } 458 if (index < CountSelectedOptions()) { 459 int iOptIndex = GetSelectedOptionIndex(index); 460 WideString csOpt = GetOptionValue(iOptIndex); 461 if (csOpt == sel_value) 462 return iOptIndex; 463 } 464 for (int i = 0; i < CountOptions(); i++) { 465 if (sel_value == GetOptionValue(i)) 466 return i; 467 } 468 return -1; 469 } 470 471 bool CPDF_FormField::ClearSelection(bool bNotify) { 472 if (bNotify && m_pForm->GetFormNotify()) { 473 WideString csValue; 474 int iIndex = GetSelectedIndex(0); 475 if (iIndex >= 0) 476 csValue = GetOptionLabel(iIndex); 477 478 if (!NotifyListOrComboBoxBeforeChange(csValue)) 479 return false; 480 } 481 m_pDict->RemoveFor("V"); 482 m_pDict->RemoveFor("I"); 483 if (bNotify) 484 NotifyListOrComboBoxAfterChange(); 485 return true; 486 } 487 488 bool CPDF_FormField::IsItemSelected(int index) const { 489 ASSERT(GetType() == ComboBox || GetType() == ListBox); 490 if (index < 0 || index >= CountOptions()) 491 return false; 492 if (IsOptionSelected(index)) 493 return true; 494 495 WideString opt_value = GetOptionValue(index); 496 CPDF_Object* pValue = FPDF_GetFieldAttr(m_pDict.Get(), "V"); 497 if (!pValue) { 498 pValue = FPDF_GetFieldAttr(m_pDict.Get(), "I"); 499 if (!pValue) 500 return false; 501 } 502 503 if (pValue->IsString()) 504 return pValue->GetUnicodeText() == opt_value; 505 506 if (pValue->IsNumber()) { 507 if (pValue->GetString().IsEmpty()) 508 return false; 509 return (pValue->GetInteger() == index); 510 } 511 512 CPDF_Array* pArray = pValue->AsArray(); 513 if (!pArray) 514 return false; 515 516 int iPos = -1; 517 for (int j = 0; j < CountSelectedOptions(); j++) { 518 if (GetSelectedOptionIndex(j) == index) { 519 iPos = j; 520 break; 521 } 522 } 523 for (int i = 0; i < static_cast<int>(pArray->GetCount()); i++) 524 if (pArray->GetDirectObjectAt(i)->GetUnicodeText() == opt_value && 525 i == iPos) { 526 return true; 527 } 528 return false; 529 } 530 531 bool CPDF_FormField::SetItemSelection(int index, bool bSelected, bool bNotify) { 532 ASSERT(GetType() == ComboBox || GetType() == ListBox); 533 if (index < 0 || index >= CountOptions()) 534 return false; 535 536 WideString opt_value = GetOptionValue(index); 537 if (bNotify && !NotifyListOrComboBoxBeforeChange(opt_value)) 538 return false; 539 540 if (bSelected) { 541 if (GetType() == ListBox) { 542 SelectOption(index, true); 543 if (!(m_Flags & kFormListMultiSelect)) { 544 m_pDict->SetNewFor<CPDF_String>("V", PDF_EncodeText(opt_value), false); 545 } else { 546 CPDF_Array* pArray = m_pDict->SetNewFor<CPDF_Array>("V"); 547 for (int i = 0; i < CountOptions(); i++) { 548 if (i == index || IsItemSelected(i)) { 549 opt_value = GetOptionValue(i); 550 pArray->AddNew<CPDF_String>(PDF_EncodeText(opt_value), false); 551 } 552 } 553 } 554 } else { 555 m_pDict->SetNewFor<CPDF_String>("V", PDF_EncodeText(opt_value), false); 556 CPDF_Array* pI = m_pDict->SetNewFor<CPDF_Array>("I"); 557 pI->AddNew<CPDF_Number>(index); 558 } 559 } else { 560 CPDF_Object* pValue = FPDF_GetFieldAttr(m_pDict.Get(), "V"); 561 if (pValue) { 562 if (GetType() == ListBox) { 563 SelectOption(index, false); 564 if (pValue->IsString()) { 565 if (pValue->GetUnicodeText() == opt_value) 566 m_pDict->RemoveFor("V"); 567 } else if (pValue->IsArray()) { 568 auto pArray = pdfium::MakeUnique<CPDF_Array>(); 569 for (int i = 0; i < CountOptions(); i++) { 570 if (i != index && IsItemSelected(i)) { 571 opt_value = GetOptionValue(i); 572 pArray->AddNew<CPDF_String>(PDF_EncodeText(opt_value), false); 573 } 574 } 575 if (pArray->GetCount() > 0) 576 m_pDict->SetFor("V", std::move(pArray)); 577 } 578 } else { 579 m_pDict->RemoveFor("V"); 580 m_pDict->RemoveFor("I"); 581 } 582 } 583 } 584 if (bNotify) 585 NotifyListOrComboBoxAfterChange(); 586 return true; 587 } 588 589 bool CPDF_FormField::IsItemDefaultSelected(int index) const { 590 ASSERT(GetType() == ComboBox || GetType() == ListBox); 591 if (index < 0 || index >= CountOptions()) 592 return false; 593 int iDVIndex = GetDefaultSelectedItem(); 594 return iDVIndex >= 0 && iDVIndex == index; 595 } 596 597 int CPDF_FormField::GetDefaultSelectedItem() const { 598 ASSERT(GetType() == ComboBox || GetType() == ListBox); 599 CPDF_Object* pValue = FPDF_GetFieldAttr(m_pDict.Get(), "DV"); 600 if (!pValue) 601 return -1; 602 WideString csDV = pValue->GetUnicodeText(); 603 if (csDV.IsEmpty()) 604 return -1; 605 for (int i = 0; i < CountOptions(); i++) { 606 if (csDV == GetOptionValue(i)) 607 return i; 608 } 609 return -1; 610 } 611 612 int CPDF_FormField::CountOptions() const { 613 CPDF_Array* pArray = ToArray(FPDF_GetFieldAttr(m_pDict.Get(), "Opt")); 614 return pArray ? pArray->GetCount() : 0; 615 } 616 617 WideString CPDF_FormField::GetOptionText(int index, int sub_index) const { 618 CPDF_Array* pArray = ToArray(FPDF_GetFieldAttr(m_pDict.Get(), "Opt")); 619 if (!pArray) 620 return WideString(); 621 622 CPDF_Object* pOption = pArray->GetDirectObjectAt(index); 623 if (!pOption) 624 return WideString(); 625 if (CPDF_Array* pOptionArray = pOption->AsArray()) 626 pOption = pOptionArray->GetDirectObjectAt(sub_index); 627 628 CPDF_String* pString = ToString(pOption); 629 return pString ? pString->GetUnicodeText() : WideString(); 630 } 631 632 WideString CPDF_FormField::GetOptionLabel(int index) const { 633 return GetOptionText(index, 1); 634 } 635 636 WideString CPDF_FormField::GetOptionValue(int index) const { 637 return GetOptionText(index, 0); 638 } 639 640 int CPDF_FormField::FindOption(WideString csOptLabel) const { 641 for (int i = 0; i < CountOptions(); i++) { 642 if (GetOptionValue(i) == csOptLabel) 643 return i; 644 } 645 return -1; 646 } 647 648 int CPDF_FormField::FindOptionValue(const WideString& csOptValue) const { 649 for (int i = 0; i < CountOptions(); i++) { 650 if (GetOptionValue(i) == csOptValue) 651 return i; 652 } 653 return -1; 654 } 655 656 #ifdef PDF_ENABLE_XFA 657 int CPDF_FormField::InsertOption(WideString csOptLabel, 658 int index, 659 bool bNotify) { 660 if (csOptLabel.IsEmpty()) 661 return -1; 662 663 if (bNotify && !NotifyListOrComboBoxBeforeChange(csOptLabel)) 664 return -1; 665 666 ByteString csStr = PDF_EncodeText(csOptLabel); 667 CPDF_Array* pOpt = ToArray(FPDF_GetFieldAttr(m_pDict.Get(), "Opt")); 668 if (!pOpt) 669 pOpt = m_pDict->SetNewFor<CPDF_Array>("Opt"); 670 671 int iCount = pdfium::base::checked_cast<int>(pOpt->GetCount()); 672 if (index >= iCount) { 673 pOpt->AddNew<CPDF_String>(csStr, false); 674 index = iCount; 675 } else { 676 pOpt->InsertNewAt<CPDF_String>(index, csStr, false); 677 } 678 679 if (bNotify) 680 NotifyListOrComboBoxAfterChange(); 681 return index; 682 } 683 684 bool CPDF_FormField::ClearOptions(bool bNotify) { 685 if (bNotify && m_pForm->GetFormNotify()) { 686 WideString csValue; 687 int iIndex = GetSelectedIndex(0); 688 if (iIndex >= 0) 689 csValue = GetOptionLabel(iIndex); 690 if (!NotifyListOrComboBoxBeforeChange(csValue)) 691 return false; 692 } 693 694 m_pDict->RemoveFor("Opt"); 695 m_pDict->RemoveFor("V"); 696 m_pDict->RemoveFor("DV"); 697 m_pDict->RemoveFor("I"); 698 m_pDict->RemoveFor("TI"); 699 700 if (bNotify) 701 NotifyListOrComboBoxAfterChange(); 702 703 return true; 704 } 705 #endif // PDF_ENABLE_XFA 706 707 bool CPDF_FormField::CheckControl(int iControlIndex, 708 bool bChecked, 709 bool bNotify) { 710 ASSERT(GetType() == CheckBox || GetType() == RadioButton); 711 CPDF_FormControl* pControl = GetControl(iControlIndex); 712 if (!pControl) 713 return false; 714 if (!bChecked && pControl->IsChecked() == bChecked) 715 return false; 716 717 WideString csWExport = pControl->GetExportValue(); 718 ByteString csBExport = PDF_EncodeText(csWExport); 719 int iCount = CountControls(); 720 bool bUnison = IsUnison(this); 721 for (int i = 0; i < iCount; i++) { 722 CPDF_FormControl* pCtrl = GetControl(i); 723 if (bUnison) { 724 WideString csEValue = pCtrl->GetExportValue(); 725 if (csEValue == csWExport) { 726 if (pCtrl->GetOnStateName() == pControl->GetOnStateName()) 727 pCtrl->CheckControl(bChecked); 728 else if (bChecked) 729 pCtrl->CheckControl(false); 730 } else if (bChecked) { 731 pCtrl->CheckControl(false); 732 } 733 } else { 734 if (i == iControlIndex) 735 pCtrl->CheckControl(bChecked); 736 else if (bChecked) 737 pCtrl->CheckControl(false); 738 } 739 } 740 741 CPDF_Object* pOpt = FPDF_GetFieldAttr(m_pDict.Get(), "Opt"); 742 if (!ToArray(pOpt)) { 743 if (bChecked) { 744 m_pDict->SetNewFor<CPDF_Name>("V", csBExport); 745 } else { 746 ByteString csV; 747 CPDF_Object* pV = FPDF_GetFieldAttr(m_pDict.Get(), "V"); 748 if (pV) 749 csV = pV->GetString(); 750 if (csV == csBExport) 751 m_pDict->SetNewFor<CPDF_Name>("V", "Off"); 752 } 753 } else if (bChecked) { 754 m_pDict->SetNewFor<CPDF_Name>("V", ByteString::Format("%d", iControlIndex)); 755 } 756 if (bNotify && m_pForm->GetFormNotify()) 757 m_pForm->GetFormNotify()->AfterCheckedStatusChange(this); 758 return true; 759 } 760 761 WideString CPDF_FormField::GetCheckValue(bool bDefault) const { 762 ASSERT(GetType() == CheckBox || GetType() == RadioButton); 763 WideString csExport = L"Off"; 764 int iCount = CountControls(); 765 for (int i = 0; i < iCount; i++) { 766 CPDF_FormControl* pControl = GetControl(i); 767 bool bChecked = 768 bDefault ? pControl->IsDefaultChecked() : pControl->IsChecked(); 769 if (bChecked) { 770 csExport = pControl->GetExportValue(); 771 break; 772 } 773 } 774 return csExport; 775 } 776 777 bool CPDF_FormField::SetCheckValue(const WideString& value, 778 bool bDefault, 779 bool bNotify) { 780 ASSERT(GetType() == CheckBox || GetType() == RadioButton); 781 int iCount = CountControls(); 782 for (int i = 0; i < iCount; i++) { 783 CPDF_FormControl* pControl = GetControl(i); 784 WideString csExport = pControl->GetExportValue(); 785 bool val = csExport == value; 786 if (!bDefault) 787 CheckControl(GetControlIndex(pControl), val); 788 if (val) 789 break; 790 } 791 if (bNotify && m_pForm->GetFormNotify()) 792 m_pForm->GetFormNotify()->AfterCheckedStatusChange(this); 793 return true; 794 } 795 796 int CPDF_FormField::GetTopVisibleIndex() const { 797 CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict.Get(), "TI"); 798 return pObj ? pObj->GetInteger() : 0; 799 } 800 801 int CPDF_FormField::CountSelectedOptions() const { 802 CPDF_Array* pArray = ToArray(FPDF_GetFieldAttr(m_pDict.Get(), "I")); 803 return pArray ? pArray->GetCount() : 0; 804 } 805 806 int CPDF_FormField::GetSelectedOptionIndex(int index) const { 807 CPDF_Array* pArray = ToArray(FPDF_GetFieldAttr(m_pDict.Get(), "I")); 808 if (!pArray) 809 return -1; 810 811 int iCount = pArray->GetCount(); 812 if (iCount < 0 || index >= iCount) 813 return -1; 814 return pArray->GetIntegerAt(index); 815 } 816 817 bool CPDF_FormField::IsOptionSelected(int iOptIndex) const { 818 CPDF_Array* pArray = ToArray(FPDF_GetFieldAttr(m_pDict.Get(), "I")); 819 if (!pArray) 820 return false; 821 822 for (const auto& pObj : *pArray) { 823 if (pObj->GetInteger() == iOptIndex) 824 return true; 825 } 826 return false; 827 } 828 829 bool CPDF_FormField::SelectOption(int iOptIndex, bool bSelected, bool bNotify) { 830 CPDF_Array* pArray = m_pDict->GetArrayFor("I"); 831 if (!pArray) { 832 if (!bSelected) 833 return true; 834 835 pArray = m_pDict->SetNewFor<CPDF_Array>("I"); 836 } 837 838 bool bReturn = false; 839 for (size_t i = 0; i < pArray->GetCount(); i++) { 840 int iFind = pArray->GetIntegerAt(i); 841 if (iFind == iOptIndex) { 842 if (bSelected) 843 return true; 844 845 if (bNotify && m_pForm->GetFormNotify()) { 846 WideString csValue = GetOptionLabel(iOptIndex); 847 if (!NotifyListOrComboBoxBeforeChange(csValue)) 848 return false; 849 } 850 pArray->RemoveAt(i); 851 bReturn = true; 852 break; 853 } 854 855 if (iFind > iOptIndex) { 856 if (!bSelected) 857 continue; 858 859 if (bNotify && m_pForm->GetFormNotify()) { 860 WideString csValue = GetOptionLabel(iOptIndex); 861 if (!NotifyListOrComboBoxBeforeChange(csValue)) 862 return false; 863 } 864 pArray->InsertNewAt<CPDF_Number>(i, iOptIndex); 865 bReturn = true; 866 break; 867 } 868 } 869 if (!bReturn) { 870 if (bSelected) 871 pArray->AddNew<CPDF_Number>(iOptIndex); 872 873 if (pArray->IsEmpty()) 874 m_pDict->RemoveFor("I"); 875 } 876 if (bNotify) 877 NotifyListOrComboBoxAfterChange(); 878 879 return true; 880 } 881 882 bool CPDF_FormField::ClearSelectedOptions(bool bNotify) { 883 if (bNotify && m_pForm->GetFormNotify()) { 884 WideString csValue; 885 int iIndex = GetSelectedIndex(0); 886 if (iIndex >= 0) 887 csValue = GetOptionLabel(iIndex); 888 889 if (!NotifyListOrComboBoxBeforeChange(csValue)) 890 return false; 891 } 892 m_pDict->RemoveFor("I"); 893 if (bNotify) 894 NotifyListOrComboBoxAfterChange(); 895 896 return true; 897 } 898 899 void CPDF_FormField::LoadDA() { 900 CPDF_Dictionary* pFormDict = m_pForm->GetFormDict(); 901 if (!pFormDict) 902 return; 903 904 ByteString DA; 905 if (CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict.Get(), "DA")) 906 DA = pObj->GetString(); 907 908 if (DA.IsEmpty()) 909 DA = pFormDict->GetStringFor("DA"); 910 911 if (DA.IsEmpty()) 912 return; 913 914 CPDF_Dictionary* pDR = pFormDict->GetDictFor("DR"); 915 if (!pDR) 916 return; 917 918 CPDF_Dictionary* pFont = pDR->GetDictFor("Font"); 919 if (!pFont) 920 return; 921 922 CPDF_SimpleParser syntax(DA.AsStringView()); 923 syntax.FindTagParamFromStart("Tf", 2); 924 ByteString font_name(syntax.GetWord()); 925 CPDF_Dictionary* pFontDict = pFont->GetDictFor(font_name); 926 if (!pFontDict) 927 return; 928 929 m_pFont = m_pForm->GetDocument()->LoadFont(pFontDict); 930 m_FontSize = FX_atof(syntax.GetWord()); 931 } 932 933 bool CPDF_FormField::NotifyBeforeSelectionChange(const WideString& value) { 934 if (!m_pForm->GetFormNotify()) 935 return true; 936 return m_pForm->GetFormNotify()->BeforeSelectionChange(this, value) >= 0; 937 } 938 939 void CPDF_FormField::NotifyAfterSelectionChange() { 940 if (!m_pForm->GetFormNotify()) 941 return; 942 m_pForm->GetFormNotify()->AfterSelectionChange(this); 943 } 944 945 bool CPDF_FormField::NotifyBeforeValueChange(const WideString& value) { 946 if (!m_pForm->GetFormNotify()) 947 return true; 948 return m_pForm->GetFormNotify()->BeforeValueChange(this, value) >= 0; 949 } 950 951 void CPDF_FormField::NotifyAfterValueChange() { 952 if (!m_pForm->GetFormNotify()) 953 return; 954 m_pForm->GetFormNotify()->AfterValueChange(this); 955 } 956 957 bool CPDF_FormField::NotifyListOrComboBoxBeforeChange(const WideString& value) { 958 switch (GetType()) { 959 case ListBox: 960 return NotifyBeforeSelectionChange(value); 961 case ComboBox: 962 return NotifyBeforeValueChange(value); 963 default: 964 return true; 965 } 966 } 967 968 void CPDF_FormField::NotifyListOrComboBoxAfterChange() { 969 switch (GetType()) { 970 case ListBox: 971 NotifyAfterSelectionChange(); 972 break; 973 case ComboBox: 974 NotifyAfterValueChange(); 975 break; 976 default: 977 break; 978 } 979 } 980