From 7e0c05d7a3329fd0a262d13b8aea74eaf33ba997 Mon Sep 17 00:00:00 2001 From: Diana Gage Date: Wed, 19 Jul 2017 17:33:33 -0700 Subject: Add FPDFAnnot_GetFormFieldFlags() and associated embedder tests. Given an interactive form annotation, this method returns its annotation flags. The flags returned are dependent upon the "Ff" field, and are specific to interactive form annotations, such as FPDF_FORMFLAG_MULTILINE, FPDF_FORMFLAG_COMBO, FPDF_FORMFLAG_EDIT, and others. To test this method more thoroughly, text_form_multiple.pdf has been added, which is similar to text_form.pdf, but includes a read-only text field. BUG=chromium:59266 Change-Id: Ie66046de273f69a1be6f04a433351ebaa271f60c Reviewed-on: https://pdfium-review.googlesource.com/7851 Commit-Queue: Diana Gage Reviewed-by: Lei Zhang Reviewed-by: dsinclair --- fpdfsdk/fpdfannot.cpp | 18 +++++++ fpdfsdk/fpdfannot_embeddertest.cpp | 69 +++++++++++++++++++++++++++ fpdfsdk/fpdfview_c_api_test.c | 1 + public/fpdf_annot.h | 38 +++++++++++++++ testing/resources/text_form_multiple.in | 69 +++++++++++++++++++++++++++ testing/resources/text_form_multiple.pdf | 82 ++++++++++++++++++++++++++++++++ 6 files changed, 277 insertions(+) create mode 100644 testing/resources/text_form_multiple.in create mode 100644 testing/resources/text_form_multiple.pdf diff --git a/fpdfsdk/fpdfannot.cpp b/fpdfsdk/fpdfannot.cpp index 1c4345ab52..f3a9ea1b72 100644 --- a/fpdfsdk/fpdfannot.cpp +++ b/fpdfsdk/fpdfannot.cpp @@ -18,6 +18,8 @@ #include "core/fpdfapi/parser/cpdf_number.h" #include "core/fpdfapi/parser/cpdf_string.h" #include "core/fpdfdoc/cpdf_annot.h" +#include "core/fpdfdoc/cpdf_formfield.h" +#include "core/fpdfdoc/cpdf_interform.h" #include "core/fpdfdoc/cpvt_color.h" #include "core/fpdfdoc/cpvt_generateap.h" #include "fpdfsdk/fsdk_define.h" @@ -786,3 +788,19 @@ DLLEXPORT FPDF_BOOL STDCALL FPDFAnnot_SetFlags(FPDF_ANNOTATION annot, pAnnotDict->SetNewFor("F", flags); return true; } + +DLLEXPORT int STDCALL FPDFAnnot_GetFormFieldFlags(FPDF_PAGE page, + FPDF_ANNOTATION annot) { + CPDF_Page* pPage = CPDFPageFromFPDFPage(page); + if (!pPage || !annot) + return FPDF_FORMFLAG_NONE; + + CPDF_Dictionary* pAnnotDict = + CPDFAnnotContextFromFPDFAnnotation(annot)->GetAnnotDict(); + if (!pAnnotDict) + return FPDF_FORMFLAG_NONE; + + CPDF_InterForm interform(pPage->m_pDocument.Get()); + CPDF_FormField* pFormField = interform.GetFieldByDict(pAnnotDict); + return pFormField ? pFormField->GetFieldFlags() : FPDF_FORMFLAG_NONE; +} diff --git a/fpdfsdk/fpdfannot_embeddertest.cpp b/fpdfsdk/fpdfannot_embeddertest.cpp index c042b764a2..b50f73f3ab 100644 --- a/fpdfsdk/fpdfannot_embeddertest.cpp +++ b/fpdfsdk/fpdfannot_embeddertest.cpp @@ -887,3 +887,72 @@ TEST_F(FPDFAnnotEmbeddertest, GetSetStringValue) { FPDFPage_CloseAnnot(new_annot); CloseSaved(); } + +TEST_F(FPDFAnnotEmbeddertest, GetFormFieldFlagsTextField) { + // Open file with form text fields. + ASSERT_TRUE(OpenDocument("text_form_multiple.pdf")); + FPDF_PAGE page = FPDF_LoadPage(document(), 0); + ASSERT_TRUE(page); + + // Retrieve the first annotation: user-editable text field. + FPDF_ANNOTATION annot = FPDFPage_GetAnnot(page, 0); + ASSERT_TRUE(annot); + + // Check that the flag values are as expected. + int flags = FPDFAnnot_GetFormFieldFlags(page, annot); + EXPECT_FALSE(flags & FPDF_FORMFLAG_READONLY); + FPDFPage_CloseAnnot(annot); + + // Retrieve the second annotation: read-only text field. + annot = FPDFPage_GetAnnot(page, 1); + ASSERT_TRUE(annot); + + // Check that the flag values are as expected. + flags = FPDFAnnot_GetFormFieldFlags(page, annot); + EXPECT_TRUE(flags & FPDF_FORMFLAG_READONLY); + FPDFPage_CloseAnnot(annot); + + UnloadPage(page); +} + +TEST_F(FPDFAnnotEmbeddertest, GetFormFieldFlagsComboBox) { + // Open file with form text fields. + ASSERT_TRUE(OpenDocument("combobox_form.pdf")); + FPDF_PAGE page = FPDF_LoadPage(document(), 0); + ASSERT_TRUE(page); + + // Retrieve the first annotation: user-editable combobox. + FPDF_ANNOTATION annot = FPDFPage_GetAnnot(page, 0); + ASSERT_TRUE(annot); + + // Check that the flag values are as expected. + int flags = FPDFAnnot_GetFormFieldFlags(page, annot); + EXPECT_FALSE(flags & FPDF_FORMFLAG_READONLY); + EXPECT_TRUE(flags & FPDF_FORMFLAG_CHOICE_COMBO); + EXPECT_TRUE(flags & FPDF_FORMFLAG_CHOICE_EDIT); + FPDFPage_CloseAnnot(annot); + + // Retrieve the second annotation: regular combobox. + annot = FPDFPage_GetAnnot(page, 1); + ASSERT_TRUE(annot); + + // Check that the flag values are as expected. + flags = FPDFAnnot_GetFormFieldFlags(page, annot); + EXPECT_FALSE(flags & FPDF_FORMFLAG_READONLY); + EXPECT_TRUE(flags & FPDF_FORMFLAG_CHOICE_COMBO); + EXPECT_FALSE(flags & FPDF_FORMFLAG_CHOICE_EDIT); + FPDFPage_CloseAnnot(annot); + + // Retrieve the third annotation: read-only combobox. + annot = FPDFPage_GetAnnot(page, 2); + ASSERT_TRUE(annot); + + // Check that the flag values are as expected. + flags = FPDFAnnot_GetFormFieldFlags(page, annot); + EXPECT_TRUE(flags & FPDF_FORMFLAG_READONLY); + EXPECT_TRUE(flags & FPDF_FORMFLAG_CHOICE_COMBO); + EXPECT_FALSE(flags & FPDF_FORMFLAG_CHOICE_EDIT); + FPDFPage_CloseAnnot(annot); + + UnloadPage(page); +} diff --git a/fpdfsdk/fpdfview_c_api_test.c b/fpdfsdk/fpdfview_c_api_test.c index 6753e66c52..1405b40ce8 100644 --- a/fpdfsdk/fpdfview_c_api_test.c +++ b/fpdfsdk/fpdfview_c_api_test.c @@ -61,6 +61,7 @@ int CheckPDFiumCApi() { CHK(FPDFAnnot_GetStringValue); CHK(FPDFAnnot_GetFlags); CHK(FPDFAnnot_SetFlags); + CHK(FPDFAnnot_GetFormFieldFlags); // fpdf_attachment.h CHK(FPDFDoc_GetAttachmentCount); diff --git a/public/fpdf_annot.h b/public/fpdf_annot.h index 1351f7193b..2a44e45bc8 100644 --- a/public/fpdf_annot.h +++ b/public/fpdf_annot.h @@ -55,6 +55,33 @@ extern "C" { #define FPDF_ANNOT_FLAG_LOCKED (1 << 7) #define FPDF_ANNOT_FLAG_TOGGLENOVIEW (1 << 8) +#define FPDF_OBJECT_UNKNOWN 0 +#define FPDF_OBJECT_BOOLEAN 1 +#define FPDF_OBJECT_NUMBER 2 +#define FPDF_OBJECT_STRING 3 +#define FPDF_OBJECT_NAME 4 +#define FPDF_OBJECT_ARRAY 5 +#define FPDF_OBJECT_DICTIONARY 6 +#define FPDF_OBJECT_STREAM 7 +#define FPDF_OBJECT_NULLOBJ 8 +#define FPDF_OBJECT_REFERENCE 9 + +// Refer to PDF Reference version 1.7 table 8.70 for field flags common to all +// interactive form field types. +#define FPDF_FORMFLAG_NONE 0 +#define FPDF_FORMFLAG_READONLY (1 << 0) +#define FPDF_FORMFLAG_REQUIRED (1 << 1) +#define FPDF_FORMFLAG_NOEXPORT (1 << 2) + +// Refer to PDF Reference version 1.7 table 8.77 for field flags specific to +// interactive form text fields. +#define FPDF_FORMFLAG_TEXT_MULTILINE (1 << 12) + +// Refer to PDF Reference version 1.7 table 8.79 for field flags specific to +// interactive form choice fields. +#define FPDF_FORMFLAG_CHOICE_COMBO (1 << 17) +#define FPDF_FORMFLAG_CHOICE_EDIT (1 << 18) + typedef enum FPDFANNOT_COLORTYPE { FPDFANNOT_COLORTYPE_Color = 0, FPDFANNOT_COLORTYPE_InteriorColor @@ -366,6 +393,17 @@ DLLEXPORT int STDCALL FPDFAnnot_GetFlags(FPDF_ANNOTATION annot); DLLEXPORT FPDF_BOOL STDCALL FPDFAnnot_SetFlags(FPDF_ANNOTATION annot, int flags); +// Experimental API. +// Get the annotation flags of |annot|, which is an interactive form +// annotation in |page|. +// +// page - handle to a page. +// annot - handle to an interactive form annotation. +// +// Returns the annotation flags specific to interactive forms. +DLLEXPORT int STDCALL FPDFAnnot_GetFormFieldFlags(FPDF_PAGE page, + FPDF_ANNOTATION annot); + #ifdef __cplusplus } // extern "C" #endif // __cplusplus diff --git a/testing/resources/text_form_multiple.in b/testing/resources/text_form_multiple.in new file mode 100644 index 0000000000..43919eb200 --- /dev/null +++ b/testing/resources/text_form_multiple.in @@ -0,0 +1,69 @@ +{{header}} +{{object 1 0}} +<< + /Type /Catalog + /Pages 2 0 R + /AcroForm << /Fields [ 4 0 R 9 0 R ] /DR 5 0 R >> +>> +endobj +{{object 2 0}} +<< /Count 1 /Kids [ 3 0 R ] /Type /Pages >> +endobj +{{object 3 0}} +<< + /Type /Page + /Parent 2 0 R + /Resources 5 0 R + /MediaBox [ 0 0 300 300 ] + /Contents 8 0 R + /Annots [ 4 0 R 9 0 R ] +>> +endobj +{{object 4 0}} +<< + /Type /Annot + /FT /Tx + /T (Text Box) + /DA (0 0 0 rg /F1 12 Tf) + /Rect [ 100 100 200 130 ] + /Subtype /Widget +>> +endobj +{{object 5 0}} +<< /Font 6 0 R >> +endobj +{{object 6 0}} +<< /F1 7 0 R >> +endobj +{{object 7 0}} << + /Type /Font + /Subtype /Type1 + /BaseFont /Helvetica +>> +endobj +{{object 8 0}} +<< /Length 51 >> +stream +BT +0 0 0 rg +/F1 12 Tf +100 150 Td +(Test Form) Tj +ET +endstream +endobj +{{object 9 0}} +<< + /Type /Annot + /FT /Tx + /Ff 1 + /T (ReadOnly) + /DA (0 0 0 rg /F1 12 Tf) + /Rect [ 100 200 200 230 ] + /Subtype /Widget +>> +endobj +{{xref}} +{{trailer}} +{{startxref}} +%%EOF diff --git a/testing/resources/text_form_multiple.pdf b/testing/resources/text_form_multiple.pdf new file mode 100644 index 0000000000..6b14cefa82 --- /dev/null +++ b/testing/resources/text_form_multiple.pdf @@ -0,0 +1,82 @@ +%PDF-1.7 +% ò¤ô +1 0 obj +<< + /Type /Catalog + /Pages 2 0 R + /AcroForm << /Fields [ 4 0 R 9 0 R ] /DR 5 0 R >> +>> +endobj +2 0 obj +<< /Count 1 /Kids [ 3 0 R ] /Type /Pages >> +endobj +3 0 obj +<< + /Type /Page + /Parent 2 0 R + /Resources 5 0 R + /MediaBox [ 0 0 300 300 ] + /Contents 8 0 R + /Annots [ 4 0 R 9 0 R ] +>> +endobj +4 0 obj +<< + /Type /Annot + /FT /Tx + /T (Text Box) + /DA (0 0 0 rg /F1 12 Tf) + /Rect [ 100 100 200 130 ] + /Subtype /Widget +>> +endobj +5 0 obj +<< /Font 6 0 R >> +endobj +6 0 obj +<< /F1 7 0 R >> +endobj +7 0 obj << + /Type /Font + /Subtype /Type1 + /BaseFont /Helvetica +>> +endobj +8 0 obj +<< /Length 51 >> +stream +BT +0 0 0 rg +/F1 12 Tf +100 150 Td +(Test Form) Tj +ET +endstream +endobj +9 0 obj +<< + /Type /Annot + /FT /Tx + /Ff 1 + /T (ReadOnly) + /DA (0 0 0 rg /F1 12 Tf) + /Rect [ 100 200 200 230 ] + /Subtype /Widget +>> +endobj +xref +0 10 +0000000000 65535 f +0000000015 00000 n +0000000120 00000 n +0000000179 00000 n +0000000321 00000 n +0000000457 00000 n +0000000490 00000 n +0000000521 00000 n +0000000597 00000 n +0000000697 00000 n +trailer<< /Root 1 0 R /Size 10 >> +startxref +841 +%%EOF -- cgit v1.2.3