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