Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
cpdf_formfield.cpp
Go to the documentation of this file.
1// Copyright 2014 The PDFium Authors
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 <map>
10#include <set>
11#include <utility>
12
13#include "constants/form_fields.h"
14#include "constants/form_flags.h"
15#include "core/fpdfapi/font/cpdf_font.h"
16#include "core/fpdfapi/page/cpdf_docpagedata.h"
17#include "core/fpdfapi/parser/cfdf_document.h"
18#include "core/fpdfapi/parser/cpdf_array.h"
19#include "core/fpdfapi/parser/cpdf_dictionary.h"
20#include "core/fpdfapi/parser/cpdf_name.h"
21#include "core/fpdfapi/parser/cpdf_number.h"
22#include "core/fpdfapi/parser/cpdf_stream.h"
23#include "core/fpdfapi/parser/cpdf_string.h"
24#include "core/fpdfapi/parser/fpdf_parser_decode.h"
25#include "core/fpdfapi/parser/fpdf_parser_utility.h"
26#include "core/fpdfdoc/cpdf_defaultappearance.h"
27#include "core/fpdfdoc/cpdf_formcontrol.h"
28#include "core/fpdfdoc/cpdf_generateap.h"
29#include "core/fpdfdoc/cpdf_interactiveform.h"
30#include "core/fxcrt/stl_util.h"
31#include "third_party/base/check.h"
32#include "third_party/base/containers/contains.h"
33
34namespace {
35
36RetainPtr<const CPDF_Object> GetFieldAttrRecursive(
37 const CPDF_Dictionary* pFieldDict,
38 const ByteString& name,
39 int nLevel) {
40 static constexpr int kGetFieldMaxRecursion = 32;
41 if (!pFieldDict || nLevel > kGetFieldMaxRecursion)
42 return nullptr;
43
44 RetainPtr<const CPDF_Object> pAttr = pFieldDict->GetDirectObjectFor(name);
45 if (pAttr)
46 return pAttr;
47
48 return GetFieldAttrRecursive(
49 pFieldDict->GetDictFor(pdfium::form_fields::kParent).Get(), name,
50 nLevel + 1);
51}
52
53bool IsComboOrListField(CPDF_FormField::Type type) {
54 switch (type) {
57 return true;
58 default:
59 return false;
60 }
61}
62
63bool HasOptField(CPDF_FormField::Type type) {
64 switch (type) {
69 return true;
70 default:
71 return false;
72 }
73}
74
75} // namespace
76
77// static
78absl::optional<FormFieldType> CPDF_FormField::IntToFormFieldType(int value) {
79 if (value >= static_cast<int>(FormFieldType::kUnknown) &&
80 value < static_cast<int>(kFormFieldTypeCount)) {
81 return static_cast<FormFieldType>(value);
82 }
83 return absl::nullopt;
84}
85
86// static
88 const CPDF_Dictionary* pFieldDict,
89 const ByteString& name) {
90 return GetFieldAttrRecursive(pFieldDict, name, 0);
91}
92
93// static
95 CPDF_Dictionary* pFieldDict,
96 const ByteString& name) {
97 return pdfium::WrapRetain(const_cast<CPDF_Object*>(
98 GetFieldAttrRecursive(pFieldDict, name, 0).Get()));
99}
100
101// static
103 const CPDF_Dictionary* pFieldDict) {
104 WideString full_name;
105 std::set<const CPDF_Dictionary*> visited;
106 const CPDF_Dictionary* pLevel = pFieldDict;
107 while (pLevel) {
108 visited.insert(pLevel);
109 WideString short_name = pLevel->GetUnicodeTextFor(pdfium::form_fields::kT);
110 if (!short_name.IsEmpty()) {
111 if (full_name.IsEmpty())
112 full_name = std::move(short_name);
113 else
114 full_name = short_name + L'.' + full_name;
115 }
116 pLevel = pLevel->GetDictFor(pdfium::form_fields::kParent).Get();
117 if (pdfium::Contains(visited, pLevel))
118 break;
119 }
120 return full_name;
121}
122
124 RetainPtr<CPDF_Dictionary> pDict)
126 InitFieldFlags();
127}
128
129CPDF_FormField::~CPDF_FormField() = default;
130
131void CPDF_FormField::InitFieldFlags() {
132 RetainPtr<const CPDF_Object> ft_attr =
133 GetFieldAttrInternal(pdfium::form_fields::kFT);
134 ByteString type_name = ft_attr ? ft_attr->GetString() : ByteString();
135 uint32_t flags = GetFieldFlags();
136 m_bRequired = flags & pdfium::form_flags::kRequired;
137 m_bNoExport = flags & pdfium::form_flags::kNoExport;
138
139 if (type_name == pdfium::form_fields::kBtn) {
140 if (flags & pdfium::form_flags::kButtonRadio) {
141 m_Type = kRadioButton;
142 m_bIsUnison = flags & pdfium::form_flags::kButtonRadiosInUnison;
143 } else if (flags & pdfium::form_flags::kButtonPushbutton) {
144 m_Type = kPushButton;
145 } else {
146 m_Type = kCheckBox;
147 m_bIsUnison = true;
148 }
149 } else if (type_name == pdfium::form_fields::kTx) {
150 if (flags & pdfium::form_flags::kTextFileSelect)
151 m_Type = kFile;
152 else if (flags & pdfium::form_flags::kTextRichText)
153 m_Type = kRichText;
154 else
155 m_Type = kText;
156 } else if (type_name == pdfium::form_fields::kCh) {
157 if (flags & pdfium::form_flags::kChoiceCombo) {
158 m_Type = kComboBox;
159 } else {
160 m_Type = kListBox;
161 m_bIsMultiSelectListBox = flags & pdfium::form_flags::kChoiceMultiSelect;
162 }
163 m_bUseSelectedIndices = UseSelectedIndicesObject();
164 } else if (type_name == pdfium::form_fields::kSig) {
165 m_Type = kSign;
166 }
167}
168
169WideString CPDF_FormField::GetFullName() const {
170 return GetFullNameForDict(m_pDict.Get());
171}
172
174 const ByteString& name) const {
175 return GetFieldAttrInternal(name);
176}
177
178RetainPtr<const CPDF_Dictionary> CPDF_FormField::GetFieldDict() const {
179 return pdfium::WrapRetain(GetFieldDictInternal());
180}
181
183 switch (m_Type) {
184 case kCheckBox:
185 case kRadioButton: {
186 int iCount = CountControls();
187 // TODO(weili): Check whether anything special needs to be done for
188 // |m_bIsUnison|.
189 for (int i = 0; i < iCount; i++) {
192 }
193 m_pForm->NotifyAfterCheckedStatusChange(this);
194 break;
195 }
196 case kComboBox:
197 case kListBox: {
199 WideString csValue;
200 int iIndex = GetDefaultSelectedItem();
201 if (iIndex >= 0)
202 csValue = GetOptionLabel(iIndex);
203 if (!NotifyListOrComboBoxBeforeChange(csValue)) {
204 return false;
205 }
207 NotifyListOrComboBoxAfterChange();
208 break;
209 }
210 case kText:
211 case kRichText:
212 case kFile:
213 default: {
214 WideString csDValue;
215 WideString csValue;
216 {
217 // Limit scope of |pDV| and |pV| because they may get invalidated
218 // during notification below.
219 RetainPtr<const CPDF_Object> pDV = GetDefaultValueObject();
220 if (pDV)
221 csDValue = pDV->GetUnicodeText();
222
223 RetainPtr<const CPDF_Object> pV = GetValueObject();
224 if (pV)
225 csValue = pV->GetUnicodeText();
226 }
227
228 bool bHasRV = !!GetFieldAttrInternal(pdfium::form_fields::kRV);
229 if (!bHasRV && (csDValue == csValue))
230 return false;
231
232 if (!m_pForm->NotifyBeforeValueChange(this, csDValue))
233 return false;
234
235 {
236 // Limit scope of |pDV| because it may get invalidated during
237 // notification below.
238 RetainPtr<const CPDF_Object> pDV = GetDefaultValueObject();
239 if (pDV) {
240 RetainPtr<CPDF_Object> pClone = pDV->Clone();
241 if (!pClone)
242 return false;
243
244 m_pDict->SetFor(pdfium::form_fields::kV, std::move(pClone));
245 if (bHasRV) {
246 m_pDict->SetFor(pdfium::form_fields::kRV, pDV->Clone());
247 }
248 } else {
249 m_pDict->RemoveFor(pdfium::form_fields::kV);
250 m_pDict->RemoveFor(pdfium::form_fields::kRV);
251 }
252 }
253 m_pForm->NotifyAfterValueChange(this);
254 break;
255 }
256 }
257 return true;
258}
259
261 return fxcrt::CollectionSize<int>(GetControls());
262}
263
265 return GetControls()[index];
266}
267
269 if (!pControl)
270 return -1;
271
272 const auto& controls = GetControls();
273 auto it = std::find(controls.begin(), controls.end(), pControl);
274 if (it == controls.end())
275 return -1;
276
277 return pdfium::base::checked_cast<int>(it - controls.begin());
278}
279
281 switch (m_Type) {
282 case kPushButton:
284 case kCheckBox:
286 case kRadioButton:
288 case kComboBox:
290 case kListBox:
292 case kText:
293 case kRichText:
294 case kFile:
296 case kSign:
298 default:
300 }
301}
302
304 RetainPtr<const CPDF_Object> pObj =
305 GetFieldAttrInternal(pdfium::form_fields::kAA);
306 return CPDF_AAction(pObj ? pObj->GetDict() : nullptr);
307}
308
309WideString CPDF_FormField::GetAlternateName() const {
310 RetainPtr<const CPDF_Object> pObj =
311 GetFieldAttrInternal(pdfium::form_fields::kTU);
312 return pObj ? pObj->GetUnicodeText() : WideString();
313}
314
315WideString CPDF_FormField::GetMappingName() const {
316 RetainPtr<const CPDF_Object> pObj =
317 GetFieldAttrInternal(pdfium::form_fields::kTM);
318 return pObj ? pObj->GetUnicodeText() : WideString();
319}
320
321uint32_t CPDF_FormField::GetFieldFlags() const {
322 RetainPtr<const CPDF_Object> pObj =
323 GetFieldAttrInternal(pdfium::form_fields::kFf);
324 return pObj ? pObj->GetInteger() : 0;
325}
326
327void CPDF_FormField::SetFieldFlags(uint32_t dwFlags) {
328 m_pDict->SetNewFor<CPDF_Number>(pdfium::form_fields::kFf,
329 static_cast<int>(dwFlags));
330}
331
332WideString CPDF_FormField::GetValue(bool bDefault) const {
334 return GetCheckValue(bDefault);
335
336 RetainPtr<const CPDF_Object> pValue =
337 bDefault ? GetDefaultValueObject() : GetValueObject();
338 if (!pValue) {
339 if (!bDefault && m_Type != kText)
340 pValue = GetDefaultValueObject();
341 if (!pValue)
342 return WideString();
343 }
344
345 switch (pValue->GetType()) {
348 return pValue->GetUnicodeText();
349 case CPDF_Object::kArray: {
350 RetainPtr<const CPDF_Object> pNewValue =
351 pValue->AsArray()->GetDirectObjectAt(0);
352 if (pNewValue)
353 return pNewValue->GetUnicodeText();
354 break;
355 }
356 default:
357 break;
358 }
359 return WideString();
360}
361
362WideString CPDF_FormField::GetValue() const {
363 return GetValue(false);
364}
365
366WideString CPDF_FormField::GetDefaultValue() const {
367 return GetValue(true);
368}
369
370bool CPDF_FormField::SetValue(const WideString& value,
371 bool bDefault,
372 NotificationOption notify) {
373 switch (GetType()) {
374 case kCheckBox:
375 case kRadioButton: {
376 SetCheckValue(value, bDefault, notify);
377 return true;
378 }
379 case kFile:
380 case kRichText:
381 case kText:
382 case kComboBox: {
383 WideString csValue = value;
384 if (notify == NotificationOption::kNotify &&
385 !m_pForm->NotifyBeforeValueChange(this, csValue)) {
386 return false;
387 }
388 ByteString key(bDefault ? pdfium::form_fields::kDV
389 : pdfium::form_fields::kV);
390 m_pDict->SetNewFor<CPDF_String>(key, csValue.AsStringView());
391
392 int iIndex;
393 if (GetType() == kComboBox) {
394 iIndex = FindOption(csValue);
395 } else {
396 iIndex = -1;
397 }
398 if (iIndex < 0) {
399 if (m_Type == kRichText && !bDefault) {
400 m_pDict->SetFor(pdfium::form_fields::kRV,
401 m_pDict->GetObjectFor(key)->Clone());
402 }
403 m_pDict->RemoveFor("I");
404 } else {
405 if (!bDefault) {
408 }
409 }
410 if (notify == NotificationOption::kNotify)
411 m_pForm->NotifyAfterValueChange(this);
412 break;
413 }
414 case kListBox: {
415 int iIndex = FindOption(value);
416 if (iIndex < 0)
417 return false;
418
419 if (bDefault && iIndex == GetDefaultSelectedItem())
420 return false;
421
422 if (notify == NotificationOption::kNotify &&
423 !m_pForm->NotifyBeforeSelectionChange(this, value)) {
424 return false;
425 }
426 if (!bDefault) {
429 }
430 if (notify == NotificationOption::kNotify)
431 m_pForm->NotifyAfterSelectionChange(this);
432 break;
433 }
434 default:
435 break;
436 }
437 return true;
438}
439
440bool CPDF_FormField::SetValue(const WideString& value,
441 NotificationOption notify) {
442 return SetValue(value, false, notify);
443}
444
446 RetainPtr<const CPDF_Object> pObj = GetFieldAttrInternal("MaxLen");
447 if (pObj)
448 return pObj->GetInteger();
449
450 for (auto& pControl : GetControls()) {
451 if (!pControl)
452 continue;
453
454 RetainPtr<const CPDF_Dictionary> pWidgetDict = pControl->GetWidgetDict();
455 if (pWidgetDict->KeyExist("MaxLen"))
456 return pWidgetDict->GetIntegerFor("MaxLen");
457 }
458 return 0;
459}
460
462 const CPDF_Object* pValue = GetValueOrSelectedIndicesObject();
463 if (!pValue)
464 return 0;
465
466 if (pValue->IsString() || pValue->IsNumber())
467 return pValue->GetString().IsEmpty() ? 0 : 1;
468 const CPDF_Array* pArray = pValue->AsArray();
469 return pArray ? fxcrt::CollectionSize<int>(*pArray) : 0;
470}
471
472int CPDF_FormField::GetSelectedIndex(int index) const {
473 const CPDF_Object* pValue = GetValueOrSelectedIndicesObject();
474 if (!pValue)
475 return -1;
476
477 if (pValue->IsNumber())
478 return pValue->GetInteger();
479
480 WideString sel_value;
481 if (pValue->IsString()) {
482 if (index != 0)
483 return -1;
484 sel_value = pValue->GetUnicodeText();
485 } else {
486 const CPDF_Array* pArray = pValue->AsArray();
487 if (!pArray || index < 0)
488 return -1;
489
490 RetainPtr<const CPDF_Object> elementValue =
491 pArray->GetDirectObjectAt(index);
492 sel_value = elementValue ? elementValue->GetUnicodeText() : WideString();
493 }
494 if (index < CountSelectedOptions()) {
495 int iOptIndex = GetSelectedOptionIndex(index);
496 WideString csOpt = GetOptionValue(iOptIndex);
497 if (csOpt == sel_value)
498 return iOptIndex;
499 }
500 for (int i = 0; i < CountOptions(); i++) {
501 if (sel_value == GetOptionValue(i))
502 return i;
503 }
504 return -1;
505}
506
508 if (notify == NotificationOption::kNotify) {
509 WideString csValue;
510 int iIndex = GetSelectedIndex(0);
511 if (iIndex >= 0)
512 csValue = GetOptionLabel(iIndex);
513 if (!NotifyListOrComboBoxBeforeChange(csValue))
514 return false;
515 }
516 m_pDict->RemoveFor(pdfium::form_fields::kV);
517 m_pDict->RemoveFor("I");
518 if (notify == NotificationOption::kNotify)
519 NotifyListOrComboBoxAfterChange();
520 return true;
521}
522
523bool CPDF_FormField::IsItemSelected(int index) const {
524 CHECK(IsComboOrListField(GetType()));
525 if (index < 0 || index >= CountOptions()) {
526 return false;
527 }
528 // First consider the /I entry if it is valid, then fall back to the /V entry.
529 return m_bUseSelectedIndices ? IsSelectedIndex(index)
531}
532
534 CHECK(IsComboOrListField(GetType()));
535 if (index < 0 || index >= CountOptions()) {
536 return false;
537 }
538 WideString opt_value = GetOptionValue(index);
539 if (notify == NotificationOption::kNotify &&
540 !NotifyListOrComboBoxBeforeChange(opt_value)) {
541 return false;
542 }
543
544 SetItemSelectionSelected(index, opt_value);
545
546 // UseSelectedIndicesObject() has a non-trivial linearithmic run-time, so run
547 // only if necessary.
548 if (!m_bUseSelectedIndices)
549 m_bUseSelectedIndices = UseSelectedIndicesObject();
550
551 if (notify == NotificationOption::kNotify)
552 NotifyListOrComboBoxAfterChange();
553 return true;
554}
555
556void CPDF_FormField::SetItemSelectionSelected(int index,
557 const WideString& opt_value) {
558 if (GetType() != kListBox) {
559 m_pDict->SetNewFor<CPDF_String>(pdfium::form_fields::kV,
560 opt_value.AsStringView());
561 auto pI = m_pDict->SetNewFor<CPDF_Array>("I");
562 pI->AppendNew<CPDF_Number>(index);
563 return;
564 }
565
566 SelectOption(index);
567 if (!m_bIsMultiSelectListBox) {
568 m_pDict->SetNewFor<CPDF_String>(pdfium::form_fields::kV,
569 opt_value.AsStringView());
570 return;
571 }
572
573 auto pArray = m_pDict->SetNewFor<CPDF_Array>(pdfium::form_fields::kV);
574 for (int i = 0; i < CountOptions(); i++) {
575 if (i == index || IsItemSelected(i))
576 pArray->AppendNew<CPDF_String>(GetOptionValue(i).AsStringView());
577 }
578}
579
581 CHECK(IsComboOrListField(GetType()));
582 RetainPtr<const CPDF_Object> pValue = GetDefaultValueObject();
583 if (!pValue)
584 return -1;
585 WideString csDV = pValue->GetUnicodeText();
586 if (csDV.IsEmpty())
587 return -1;
588 for (int i = 0; i < CountOptions(); i++) {
589 if (csDV == GetOptionValue(i))
590 return i;
591 }
592 return -1;
593}
594
596 CHECK(HasOptField(GetType()));
597 RetainPtr<const CPDF_Array> pArray = ToArray(GetFieldAttrInternal("Opt"));
598 return pArray ? fxcrt::CollectionSize<int>(*pArray) : 0;
599}
600
601WideString CPDF_FormField::GetOptionText(int index, int sub_index) const {
602 CHECK(HasOptField(GetType()));
603 RetainPtr<const CPDF_Array> pArray = ToArray(GetFieldAttrInternal("Opt"));
604 if (!pArray)
605 return WideString();
606
607 RetainPtr<const CPDF_Object> pOption = pArray->GetDirectObjectAt(index);
608 if (!pOption)
609 return WideString();
610
611 const CPDF_Array* pOptionArray = pOption->AsArray();
612 if (pOptionArray)
613 pOption = pOptionArray->GetDirectObjectAt(sub_index);
614
615 if (!pOption)
616 return WideString();
617
618 const CPDF_String* pString = pOption->AsString();
619 return pString ? pString->GetUnicodeText() : WideString();
620}
621
622WideString CPDF_FormField::GetOptionLabel(int index) const {
623 return GetOptionText(index, 1);
624}
625
626WideString CPDF_FormField::GetOptionValue(int index) const {
627 return GetOptionText(index, 0);
628}
629
630int CPDF_FormField::FindOption(const WideString& csOptValue) const {
631 for (int i = 0; i < CountOptions(); i++) {
632 if (GetOptionValue(i) == csOptValue)
633 return i;
634 }
635 return -1;
636}
637
638bool CPDF_FormField::CheckControl(int iControlIndex,
639 bool bChecked,
640 NotificationOption notify) {
641 DCHECK(GetType() == kCheckBox || GetType() == kRadioButton);
642 CPDF_FormControl* pControl = GetControl(iControlIndex);
643 if (!pControl)
644 return false;
645 if (!bChecked && pControl->IsChecked() == bChecked)
646 return false;
647
648 const WideString csWExport = pControl->GetExportValue();
649 int iCount = CountControls();
650 for (int i = 0; i < iCount; i++) {
652 if (m_bIsUnison) {
653 WideString csEValue = pCtrl->GetExportValue();
654 if (csEValue == csWExport) {
656 pCtrl->CheckControl(bChecked);
657 else if (bChecked)
658 pCtrl->CheckControl(false);
659 } else if (bChecked) {
660 pCtrl->CheckControl(false);
661 }
662 } else {
663 if (i == iControlIndex)
664 pCtrl->CheckControl(bChecked);
665 else if (bChecked)
666 pCtrl->CheckControl(false);
667 }
668 }
669
670 RetainPtr<const CPDF_Object> pOpt = GetFieldAttrInternal("Opt");
671 if (!ToArray(pOpt)) {
672 ByteString csBExport = PDF_EncodeText(csWExport.AsStringView());
673 if (bChecked) {
674 m_pDict->SetNewFor<CPDF_Name>(pdfium::form_fields::kV, csBExport);
675 } else {
676 ByteString csV;
677 const CPDF_Object* pV = GetValueObject();
678 if (pV)
679 csV = pV->GetString();
680 if (csV == csBExport)
681 m_pDict->SetNewFor<CPDF_Name>(pdfium::form_fields::kV, "Off");
682 }
683 } else if (bChecked) {
684 m_pDict->SetNewFor<CPDF_Name>(pdfium::form_fields::kV,
685 ByteString::FormatInteger(iControlIndex));
686 }
687 if (notify == NotificationOption::kNotify)
688 m_pForm->NotifyAfterCheckedStatusChange(this);
689 return true;
690}
691
692WideString CPDF_FormField::GetCheckValue(bool bDefault) const {
693 DCHECK(GetType() == kCheckBox || GetType() == kRadioButton);
694 WideString csExport = L"Off";
695 int iCount = CountControls();
696 for (int i = 0; i < iCount; i++) {
697 CPDF_FormControl* pControl = GetControl(i);
698 bool bChecked =
699 bDefault ? pControl->IsDefaultChecked() : pControl->IsChecked();
700 if (bChecked) {
701 csExport = pControl->GetExportValue();
702 break;
703 }
704 }
705 return csExport;
706}
707
708bool CPDF_FormField::SetCheckValue(const WideString& value,
709 bool bDefault,
710 NotificationOption notify) {
711 DCHECK(GetType() == kCheckBox || GetType() == kRadioButton);
712 int iCount = CountControls();
713 for (int i = 0; i < iCount; i++) {
714 CPDF_FormControl* pControl = GetControl(i);
715 WideString csExport = pControl->GetExportValue();
716 bool val = csExport == value;
717 if (!bDefault) {
720 }
721 if (val)
722 break;
723 }
724 if (notify == NotificationOption::kNotify)
725 m_pForm->NotifyAfterCheckedStatusChange(this);
726 return true;
727}
728
730 RetainPtr<const CPDF_Object> pObj = GetFieldAttrInternal("TI");
731 return pObj ? pObj->GetInteger() : 0;
732}
733
735 RetainPtr<const CPDF_Array> pArray = ToArray(GetSelectedIndicesObject());
736 return pArray ? fxcrt::CollectionSize<int>(*pArray) : 0;
737}
738
740 if (index < 0)
741 return 0;
742
743 RetainPtr<const CPDF_Array> pArray = ToArray(GetSelectedIndicesObject());
744 if (!pArray)
745 return -1;
746
747 return index < fxcrt::CollectionSize<int>(*pArray)
748 ? pArray->GetIntegerAt(index)
749 : -1;
750}
751
752bool CPDF_FormField::IsSelectedOption(const WideString& wsOptValue) const {
753 RetainPtr<const CPDF_Object> pValueObject = GetValueObject();
754 if (!pValueObject)
755 return false;
756
757 const CPDF_Array* pValueArray = pValueObject->AsArray();
758 if (pValueArray) {
759 CPDF_ArrayLocker locker(pValueArray);
760 for (const auto& pObj : locker) {
761 if (pObj->IsString() && pObj->GetUnicodeText() == wsOptValue)
762 return true;
763 }
764 }
765
766 return pValueObject->IsString() &&
767 pValueObject->GetUnicodeText() == wsOptValue;
768}
769
770bool CPDF_FormField::IsSelectedIndex(int iOptIndex) const {
771 RetainPtr<const CPDF_Object> pSelectedIndicesObject =
772 GetSelectedIndicesObject();
773 if (!pSelectedIndicesObject)
774 return false;
775
776 const CPDF_Array* pSelectedIndicesArray = pSelectedIndicesObject->AsArray();
777 if (pSelectedIndicesArray) {
778 CPDF_ArrayLocker locker(pSelectedIndicesArray);
779 for (const auto& pObj : locker) {
780 if (pObj->IsNumber() && pObj->GetInteger() == iOptIndex)
781 return true;
782 }
783 }
784
785 return pSelectedIndicesObject->IsNumber() &&
786 pSelectedIndicesObject->GetInteger() == iOptIndex;
787}
788
789void CPDF_FormField::SelectOption(int iOptIndex) {
790 RetainPtr<CPDF_Array> pArray = m_pDict->GetOrCreateArrayFor("I");
791 for (size_t i = 0; i < pArray->size(); i++) {
792 int iFind = pArray->GetIntegerAt(i);
793 if (iFind == iOptIndex)
794 return;
795
796 if (iFind > iOptIndex) {
797 pArray->InsertNewAt<CPDF_Number>(i, iOptIndex);
798 return;
799 }
800 }
801 pArray->AppendNew<CPDF_Number>(iOptIndex);
802}
803
805 CHECK(IsComboOrListField(GetType()));
806
807 RetainPtr<const CPDF_Object> pSelectedIndicesObject =
808 GetSelectedIndicesObject();
809 if (!pSelectedIndicesObject)
810 return false;
811
812 // If there's not value object, then just use the indices object.
813 RetainPtr<const CPDF_Object> pValueObject = GetValueObject();
814 if (!pValueObject)
815 return true;
816
817 // Verify that the selected indices object is either an array or a number and
818 // count the number of indices.
819 size_t selected_indices_size;
820 const CPDF_Array* pSelectedIndicesArray = pSelectedIndicesObject->AsArray();
821 if (pSelectedIndicesArray)
822 selected_indices_size = pSelectedIndicesArray->size();
823 else if (pSelectedIndicesObject->IsNumber())
824 selected_indices_size = 1;
825 else
826 return false;
827
828 // Verify that the number of values is equal to |selected_indices_size|. Then,
829 // count the number of occurrences of each of the distinct values in the
830 // values object.
831 std::map<WideString, size_t> values;
832 const CPDF_Array* pValueArray = pValueObject->AsArray();
833 if (pValueArray) {
834 if (pValueArray->size() != selected_indices_size)
835 return false;
836 CPDF_ArrayLocker locker(pValueArray);
837 for (const auto& pObj : locker) {
838 if (pObj->IsString())
839 values[pObj->GetUnicodeText()]++;
840 }
841 } else if (pValueObject->IsString()) {
842 if (selected_indices_size != 1)
843 return false;
844 values[pValueObject->GetUnicodeText()]++;
845 }
846
847 // Validate each index in the selected indices object. Then, verify that items
848 // identified by selected indices entry do not differ from those in the values
849 // entry of the field dictionary.
850 const int num_options = CountOptions();
851 if (pSelectedIndicesArray) {
852 CPDF_ArrayLocker locker(pSelectedIndicesArray);
853 for (const auto& pObj : locker) {
854 if (!pObj->IsNumber())
855 return false;
856
857 int index = pObj->GetInteger();
858 if (index < 0 || index >= num_options)
859 return false;
860
861 WideString wsOptValue = GetOptionValue(index);
862 auto it = values.find(wsOptValue);
863 if (it == values.end())
864 return false;
865
866 it->second--;
867 if (it->second == 0)
868 values.erase(it);
869 }
870
871 return values.empty();
872 }
873
874 DCHECK(pSelectedIndicesObject->IsNumber());
875 int index = pSelectedIndicesObject->GetInteger();
876 if (index < 0 || index >= num_options)
877 return false;
878
879 return pdfium::Contains(values, GetOptionValue(index));
880}
881
882bool CPDF_FormField::NotifyListOrComboBoxBeforeChange(const WideString& value) {
883 switch (GetType()) {
884 case kListBox:
885 return m_pForm->NotifyBeforeSelectionChange(this, value);
886 case kComboBox:
887 return m_pForm->NotifyBeforeValueChange(this, value);
888 default:
889 return true;
890 }
891}
892
893void CPDF_FormField::NotifyListOrComboBoxAfterChange() {
894 switch (GetType()) {
895 case kListBox:
896 m_pForm->NotifyAfterSelectionChange(this);
897 break;
898 case kComboBox:
899 m_pForm->NotifyAfterValueChange(this);
900 break;
901 default:
902 break;
903 }
904}
905
906RetainPtr<const CPDF_Object> CPDF_FormField::GetFieldAttrInternal(
907 const ByteString& name) const {
908 return GetFieldAttrRecursive(m_pDict.Get(), name, 0);
909}
910
911const CPDF_Dictionary* CPDF_FormField::GetFieldDictInternal() const {
912 return m_pDict.Get();
913}
914
915RetainPtr<const CPDF_Object> CPDF_FormField::GetDefaultValueObject() const {
916 return GetFieldAttrInternal(pdfium::form_fields::kDV);
917}
918
919RetainPtr<const CPDF_Object> CPDF_FormField::GetValueObject() const {
920 return GetFieldAttrInternal(pdfium::form_fields::kV);
921}
922
923RetainPtr<const CPDF_Object> CPDF_FormField::GetSelectedIndicesObject() const {
924 CHECK(IsComboOrListField(GetType()));
925 return GetFieldAttrInternal("I");
926}
927
928RetainPtr<const CPDF_Object> CPDF_FormField::GetValueOrSelectedIndicesObject()
929 const {
930 CHECK(IsComboOrListField(GetType()));
931 RetainPtr<const CPDF_Object> pValue = GetValueObject();
932 return pValue ? pValue : GetSelectedIndicesObject();
933}
934
935const std::vector<UnownedPtr<CPDF_FormControl>>& CPDF_FormField::GetControls()
936 const {
937 return m_pForm->GetControlsForField(this);
938}
CPDF_ArrayLocker(const CPDF_Array *pArray)
RetainPtr< const CPDF_Dictionary > GetDictFor(const ByteString &key) const
WideString GetUnicodeTextFor(const ByteString &key) const
WideString GetExportValue() const
ByteString GetOnStateName() const
void CheckControl(bool bChecked)
bool IsDefaultChecked() const
RetainPtr< const CPDF_Object > GetFieldAttr(const ByteString &name) const
int GetSelectedIndex(int index) const
bool IsSelectedIndex(int iOptIndex) const
bool UseSelectedIndicesObject() const
static WideString GetFullNameForDict(const CPDF_Dictionary *pFieldDict)
int CountOptions() const
int GetDefaultSelectedItem() const
bool IsSelectedOption(const WideString &wsOptValue) const
void SelectOption(int iOptIndex)
WideString GetMappingName() const
WideString GetValue() const
WideString GetFullName() const
static RetainPtr< const CPDF_Object > GetFieldAttrForDict(const CPDF_Dictionary *pFieldDict, const ByteString &name)
int CountControls() const
int FindOption(const WideString &csOptValue) const
uint32_t GetFieldFlags() const
WideString GetAlternateName() const
bool ClearSelection(NotificationOption notify)
int GetControlIndex(const CPDF_FormControl *pControl) const
int GetSelectedOptionIndex(int index) const
bool SetItemSelection(int index, NotificationOption notify)
int GetMaxLen() const
bool IsItemSelected(int index) const
static RetainPtr< CPDF_Object > GetMutableFieldAttrForDict(CPDF_Dictionary *pFieldDict, const ByteString &name)
WideString GetOptionLabel(int index) const
int CountSelectedOptions() const
int CountSelectedItems() const
WideString GetCheckValue(bool bDefault) const
CPDF_FormControl * GetControl(int index) const
int GetTopVisibleIndex() const
Type GetType() const
FormFieldType GetFieldType() const
WideString GetOptionValue(int index) const
CPDF_AAction GetAdditionalAction() const
RetainPtr< const CPDF_Dictionary > GetFieldDict() const
WideString GetDefaultValue() const
CPDF_FormField(CPDF_InteractiveForm *pForm, RetainPtr< CPDF_Dictionary > pDict)
bool CheckControl(int iControlIndex, bool bChecked, NotificationOption notify)
void SetFieldFlags(uint32_t dwFlags)
bool SetValue(const WideString &value, NotificationOption notify)
virtual WideString GetUnicodeText() const
virtual ByteString GetString() const
const CPDF_Array * AsArray() const
virtual int GetInteger() const
bool IsString() const
bool IsNumber() const
WideString GetUnicodeText() const override
ByteString(const char *ptr)
bool operator==(const ByteString &other) const
bool operator==(const char *ptr) const
ByteString & operator=(ByteString &&that) noexcept
bool IsEmpty() const
Definition bytestring.h:119
bool operator==(const WideString &other) const
WideString & operator=(WideString &&that) noexcept
bool IsEmpty() const
Definition widestring.h:118
NotificationOption
FormFieldType
WideString operator+(const WideString &str1, const WideString &str2)
Definition widestring.h:269
WideString operator+(const WideString &str1, wchar_t ch)
Definition widestring.h:272
const char kParent[]
constexpr uint32_t kButtonPushbutton
Definition form_flags.h:21
constexpr uint32_t kTextFileSelect
Definition form_flags.h:28
constexpr uint32_t kButtonRadiosInUnison
Definition form_flags.h:22
constexpr uint32_t kChoiceCombo
Definition form_flags.h:36
constexpr uint32_t kRequired
Definition form_flags.h:14
constexpr uint32_t kButtonRadio
Definition form_flags.h:20
constexpr uint32_t kChoiceMultiSelect
Definition form_flags.h:39
constexpr uint32_t kNoExport
Definition form_flags.h:15
constexpr uint32_t kTextRichText
Definition form_flags.h:32
#define CHECK(cvref)