Adding API to check if an option in a choice form field is selected.
This change adds a public API to determine whether or not the option at
|index| in |annot|'s "Opt" dictionary is selected. The API
FPDFAnnot_IsOptionSelected() is added in fpdf_annot.h and is intended
for use with listbox and combobox widget annotations.
This CL also includes tests to validate the API for listbox and combobox
widget annotations.
Bug: pdfium:1526
Change-Id: I4bd2ae6805ef348f1c34dca7e1136824490314f4
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/69790
Reviewed-by: Lei Zhang <thestig@chromium.org>
Commit-Queue: Mansi Awasthi <maawas@microsoft.com>
diff --git a/fpdfsdk/fpdf_annot.cpp b/fpdfsdk/fpdf_annot.cpp
index d02b1fc..b414c8f 100644
--- a/fpdfsdk/fpdf_annot.cpp
+++ b/fpdfsdk/fpdf_annot.cpp
@@ -1057,6 +1057,25 @@
}
FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
+FPDFAnnot_IsOptionSelected(FPDF_FORMHANDLE handle,
+ FPDF_ANNOTATION annot,
+ int index) {
+ if (index < 0)
+ return false;
+
+ CPDF_FormField* form_field = GetFormField(handle, annot);
+ if (!form_field || index >= form_field->CountOptions())
+ return false;
+
+ if (form_field->GetFieldType() != FormFieldType::kComboBox &&
+ form_field->GetFieldType() != FormFieldType::kListBox) {
+ return false;
+ }
+
+ return form_field->IsItemSelected(index);
+}
+
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDFAnnot_GetFontSize(FPDF_FORMHANDLE hHandle,
FPDF_ANNOTATION annot,
float* value) {
diff --git a/fpdfsdk/fpdf_annot_embeddertest.cpp b/fpdfsdk/fpdf_annot_embeddertest.cpp
index 6eccf74..686fe95 100644
--- a/fpdfsdk/fpdf_annot_embeddertest.cpp
+++ b/fpdfsdk/fpdf_annot_embeddertest.cpp
@@ -2049,6 +2049,147 @@
UnloadPage(page);
}
+TEST_F(FPDFAnnotEmbedderTest, IsOptionSelectedCombobox) {
+ // Open a file with combobox widget annotations and load its first page.
+ ASSERT_TRUE(OpenDocument("combobox_form.pdf"));
+ FPDF_PAGE page = LoadPage(0);
+ ASSERT_TRUE(page);
+
+ {
+ ScopedFPDFAnnotation annot(FPDFPage_GetAnnot(page, 0));
+ ASSERT_TRUE(annot);
+
+ // Checks for Combobox with no Values (/V) or Selected Indices (/I) objects.
+ int count = FPDFAnnot_GetOptionCount(form_handle(), annot.get());
+ ASSERT_EQ(3, count);
+ for (int i = 0; i < count; i++) {
+ EXPECT_FALSE(FPDFAnnot_IsOptionSelected(form_handle(), annot.get(), i));
+ }
+
+ annot.reset(FPDFPage_GetAnnot(page, 1));
+ ASSERT_TRUE(annot);
+
+ // Checks for Combobox with Values (/V) object which is just a string.
+ count = FPDFAnnot_GetOptionCount(form_handle(), annot.get());
+ ASSERT_EQ(26, count);
+ for (int i = 0; i < count; i++) {
+ EXPECT_EQ(i == 1,
+ FPDFAnnot_IsOptionSelected(form_handle(), annot.get(), i));
+ }
+
+ // Checks for index outside bound i.e. (index >= CountOption()).
+ EXPECT_FALSE(FPDFAnnot_IsOptionSelected(form_handle(), annot.get(),
+ /*index=*/26));
+ // Checks for negetive index.
+ EXPECT_FALSE(FPDFAnnot_IsOptionSelected(form_handle(), annot.get(),
+ /*index=*/-1));
+
+ // Checks for bad form handle/annot.
+ EXPECT_FALSE(FPDFAnnot_IsOptionSelected(nullptr, nullptr, /*index=*/0));
+ EXPECT_FALSE(
+ FPDFAnnot_IsOptionSelected(form_handle(), nullptr, /*index=*/0));
+ EXPECT_FALSE(FPDFAnnot_IsOptionSelected(nullptr, annot.get(), /*index=*/0));
+ }
+
+ UnloadPage(page);
+}
+
+TEST_F(FPDFAnnotEmbedderTest, IsOptionSelectedListbox) {
+ // Open a file with listbox widget annotations and load its first page.
+ ASSERT_TRUE(OpenDocument("listbox_form.pdf"));
+ FPDF_PAGE page = LoadPage(0);
+ ASSERT_TRUE(page);
+
+ {
+ ScopedFPDFAnnotation annot(FPDFPage_GetAnnot(page, 0));
+ ASSERT_TRUE(annot);
+
+ // Checks for Listbox with no Values (/V) or Selected Indices (/I) objects.
+ int count = FPDFAnnot_GetOptionCount(form_handle(), annot.get());
+ ASSERT_EQ(3, count);
+ for (int i = 0; i < count; i++) {
+ EXPECT_FALSE(FPDFAnnot_IsOptionSelected(form_handle(), annot.get(), i));
+ }
+
+ annot.reset(FPDFPage_GetAnnot(page, 1));
+ ASSERT_TRUE(annot);
+
+ // Checks for Listbox with Values (/V) object which is just a string.
+ count = FPDFAnnot_GetOptionCount(form_handle(), annot.get());
+ ASSERT_EQ(26, count);
+ for (int i = 0; i < count; i++) {
+ EXPECT_EQ(i == 1,
+ FPDFAnnot_IsOptionSelected(form_handle(), annot.get(), i));
+ }
+
+ annot.reset(FPDFPage_GetAnnot(page, 3));
+ ASSERT_TRUE(annot);
+
+ // Checks for Listbox with only Selected indices (/I) object which is an
+ // array with multiple objects.
+ count = FPDFAnnot_GetOptionCount(form_handle(), annot.get());
+ ASSERT_EQ(5, count);
+ for (int i = 0; i < count; i++) {
+ bool expected = (i == 1 || i == 3);
+ EXPECT_EQ(expected,
+ FPDFAnnot_IsOptionSelected(form_handle(), annot.get(), i));
+ }
+
+ annot.reset(FPDFPage_GetAnnot(page, 4));
+ ASSERT_TRUE(annot);
+
+ // Checks for Listbox with Values (/V) object which is an array with
+ // multiple objects.
+ count = FPDFAnnot_GetOptionCount(form_handle(), annot.get());
+ ASSERT_EQ(5, count);
+ for (int i = 0; i < count; i++) {
+ bool expected = (i == 2 || i == 4);
+ EXPECT_EQ(expected,
+ FPDFAnnot_IsOptionSelected(form_handle(), annot.get(), i));
+ }
+
+ annot.reset(FPDFPage_GetAnnot(page, 5));
+ ASSERT_TRUE(annot);
+
+ // Checks for Listbox with both Values (/V) and Selected Indices (/I)
+ // objects conflict with different lengths.
+ count = FPDFAnnot_GetOptionCount(form_handle(), annot.get());
+ ASSERT_EQ(5, count);
+ for (int i = 0; i < count; i++) {
+ bool expected = (i == 0 || i == 2);
+ EXPECT_EQ(expected,
+ FPDFAnnot_IsOptionSelected(form_handle(), annot.get(), i));
+ }
+ }
+
+ UnloadPage(page);
+}
+
+TEST_F(FPDFAnnotEmbedderTest, IsOptionSelectedInvalidAnnotations) {
+ // Open a file with multiple form field annotations and load its first page.
+ ASSERT_TRUE(OpenDocument("multiple_form_types.pdf"));
+ FPDF_PAGE page = LoadPage(0);
+ ASSERT_TRUE(page);
+
+ {
+ ScopedFPDFAnnotation annot(FPDFPage_GetAnnot(page, 0));
+ ASSERT_TRUE(annot);
+
+ // Checks for link annotation.
+ EXPECT_FALSE(FPDFAnnot_IsOptionSelected(form_handle(), annot.get(),
+ /*index=*/0));
+
+ annot.reset(FPDFPage_GetAnnot(page, 3));
+ ASSERT_TRUE(annot);
+
+ // Checks for text field annotation.
+ EXPECT_FALSE(FPDFAnnot_IsOptionSelected(form_handle(), annot.get(),
+ /*index=*/0));
+ }
+
+ UnloadPage(page);
+}
+
TEST_F(FPDFAnnotEmbedderTest, GetFontSizeCombobox) {
// Open a file with combobox annotations and load its first page.
ASSERT_TRUE(OpenDocument("combobox_form.pdf"));
diff --git a/fpdfsdk/fpdf_view_c_api_test.c b/fpdfsdk/fpdf_view_c_api_test.c
index aebffe5..c2c77d6 100644
--- a/fpdfsdk/fpdf_view_c_api_test.c
+++ b/fpdfsdk/fpdf_view_c_api_test.c
@@ -70,6 +70,7 @@
CHK(FPDFAnnot_HasKey);
CHK(FPDFAnnot_IsChecked);
CHK(FPDFAnnot_IsObjectSupportedSubtype);
+ CHK(FPDFAnnot_IsOptionSelected);
CHK(FPDFAnnot_IsSupportedSubtype);
CHK(FPDFAnnot_RemoveInkList);
CHK(FPDFAnnot_RemoveObject);
diff --git a/public/fpdf_annot.h b/public/fpdf_annot.h
index f764ed3..b1fe901 100644
--- a/public/fpdf_annot.h
+++ b/public/fpdf_annot.h
@@ -81,6 +81,7 @@
// interactive form choice fields.
#define FPDF_FORMFLAG_CHOICE_COMBO (1 << 17)
#define FPDF_FORMFLAG_CHOICE_EDIT (1 << 18)
+#define FPDF_FORMFLAG_CHOICE_MULTI_SELECT (1 << 21)
typedef enum FPDFANNOT_COLORTYPE {
FPDFANNOT_COLORTYPE_Color = 0,
@@ -656,6 +657,22 @@
unsigned long buflen);
// Experimental API.
+// Determine whether or not the option at |index| in |annot|'s "Opt" dictionary
+// is selected. Intended for use with listbox and combobox widget annotations.
+//
+// handle - handle to the form fill module, returned by
+// FPDFDOC_InitFormFillEnvironment.
+// annot - handle to an annotation.
+// index - numeric index of the option in the "Opt" array.
+//
+// Returns true if the option at |index| in |annot|'s "Opt" dictionary is
+// selected, false otherwise.
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
+FPDFAnnot_IsOptionSelected(FPDF_FORMHANDLE handle,
+ FPDF_ANNOTATION annot,
+ int index);
+
+// Experimental API.
// Get the float value of the font size for an |annot| with variable text.
// If 0, the font is to be auto-sized: its size is computed as a function of
// the height of the annotation rectangle.