diff options
-rw-r--r-- | core/fpdfdoc/cpdf_annot.cpp | 2 | ||||
-rw-r--r-- | core/fpdfdoc/cpdf_annot.h | 3 | ||||
-rw-r--r-- | fpdfsdk/cpdfsdk_helpers.cpp | 35 | ||||
-rw-r--r-- | fpdfsdk/cpdfsdk_helpers.h | 10 | ||||
-rw-r--r-- | fpdfsdk/fpdf_annot.cpp | 108 | ||||
-rw-r--r-- | fpdfsdk/fpdf_annot_embeddertest.cpp | 99 | ||||
-rw-r--r-- | fpdfsdk/fpdf_doc.cpp | 15 | ||||
-rw-r--r-- | fpdfsdk/fpdf_view_c_api_test.c | 1 | ||||
-rw-r--r-- | public/fpdf_annot.h | 28 | ||||
-rw-r--r-- | samples/pdfium_test_write_helper.cc | 25 |
10 files changed, 265 insertions, 61 deletions
diff --git a/core/fpdfdoc/cpdf_annot.cpp b/core/fpdfdoc/cpdf_annot.cpp index 42bda6e319..ef803c428d 100644 --- a/core/fpdfdoc/cpdf_annot.cpp +++ b/core/fpdfdoc/cpdf_annot.cpp @@ -229,7 +229,7 @@ CFX_FloatRect CPDF_Annot::RectFromQuadPointsArray(const CPDF_Array* pArray, // static CFX_FloatRect CPDF_Annot::BoundingRectFromQuadPoints( - CPDF_Dictionary* pAnnotDict) { + const CPDF_Dictionary* pAnnotDict) { CPDF_Array* pArray = pAnnotDict->GetArrayFor("QuadPoints"); if (!pArray) return CFX_FloatRect(); diff --git a/core/fpdfdoc/cpdf_annot.h b/core/fpdfdoc/cpdf_annot.h index 3f1164ad18..b2875949a3 100644 --- a/core/fpdfdoc/cpdf_annot.h +++ b/core/fpdfdoc/cpdf_annot.h @@ -69,7 +69,8 @@ class CPDF_Annot { static ByteString AnnotSubtypeToString(CPDF_Annot::Subtype nSubtype); static CFX_FloatRect RectFromQuadPointsArray(const CPDF_Array* pArray, size_t nIndex); - static CFX_FloatRect BoundingRectFromQuadPoints(CPDF_Dictionary* pAnnotDict); + static CFX_FloatRect BoundingRectFromQuadPoints( + const CPDF_Dictionary* pAnnotDict); static CFX_FloatRect RectFromQuadPoints(CPDF_Dictionary* pAnnotDict, size_t nIndex); static size_t QuadPointCount(const CPDF_Array* pArray); diff --git a/fpdfsdk/cpdfsdk_helpers.cpp b/fpdfsdk/cpdfsdk_helpers.cpp index 45c2674a4d..19252f7c5b 100644 --- a/fpdfsdk/cpdfsdk_helpers.cpp +++ b/fpdfsdk/cpdfsdk_helpers.cpp @@ -19,6 +19,8 @@ namespace { +constexpr char kQuadPoints[] = "QuadPoints"; + FPDF_DOCUMENT FPDFDocumentFromUnderlying(UnderlyingDocumentType* doc) { return static_cast<FPDF_DOCUMENT>(doc); } @@ -429,10 +431,41 @@ CFX_FloatRect CFXFloatRectFromFSRECTF(const FS_RECTF& rect) { return CFX_FloatRect(rect.left, rect.bottom, rect.right, rect.top); } -const CPDF_Array* GetQuadPointsArrayFromDictionary(CPDF_Dictionary* dict) { +CPDF_Array* GetQuadPointsArrayFromDictionary(const CPDF_Dictionary* dict) { return dict ? dict->GetArrayFor("QuadPoints") : nullptr; } +CPDF_Array* AddQuadPointsArrayToDictionary(CPDF_Dictionary* dict) { + if (!dict) + return nullptr; + return dict->SetNewFor<CPDF_Array>(kQuadPoints); +} + +bool IsValidQuadPointsIndex(const CPDF_Array* array, size_t index) { + return array && index < array->GetCount() / 8; +} + +bool GetQuadPointsAtIndex(const CPDF_Array* array, + size_t quad_index, + FS_QUADPOINTSF* quad_points) { + ASSERT(quad_points); + ASSERT(array); + + if (!IsValidQuadPointsIndex(array, quad_index)) + return false; + + quad_index *= 8; + quad_points->x1 = array->GetNumberAt(quad_index); + quad_points->y1 = array->GetNumberAt(quad_index + 1); + quad_points->x2 = array->GetNumberAt(quad_index + 2); + quad_points->y2 = array->GetNumberAt(quad_index + 3); + quad_points->x3 = array->GetNumberAt(quad_index + 4); + quad_points->y3 = array->GetNumberAt(quad_index + 5); + quad_points->x4 = array->GetNumberAt(quad_index + 6); + quad_points->y4 = array->GetNumberAt(quad_index + 7); + return true; +} + bool GetQuadPointsFromDictionary(CPDF_Dictionary* dict, size_t quad_index, FS_QUADPOINTSF* quad_points) { diff --git a/fpdfsdk/cpdfsdk_helpers.h b/fpdfsdk/cpdfsdk_helpers.h index dcd0cc9558..a5e03292a0 100644 --- a/fpdfsdk/cpdfsdk_helpers.h +++ b/fpdfsdk/cpdfsdk_helpers.h @@ -63,10 +63,12 @@ RetainPtr<IFX_SeekableStream> MakeSeekableStream( FPDF_FILEHANDLER* pFileHandler); #endif // PDF_ENABLE_XFA -const CPDF_Array* GetQuadPointsArrayFromDictionary(CPDF_Dictionary* dict); -bool GetQuadPointsFromDictionary(CPDF_Dictionary* dict, - size_t quad_index, - FS_QUADPOINTSF* quad_points); +CPDF_Array* GetQuadPointsArrayFromDictionary(const CPDF_Dictionary* dict); +CPDF_Array* AddQuadPointsArrayToDictionary(CPDF_Dictionary* dict); +bool IsValidQuadPointsIndex(const CPDF_Array* array, size_t index); +bool GetQuadPointsAtIndex(const CPDF_Array* array, + size_t quad_index, + FS_QUADPOINTSF* quad_points); CFX_FloatRect CFXFloatRectFromFSRECTF(const FS_RECTF& rect); void FSRECTFFromCFXFloatRect(const CFX_FloatRect& rect, FS_RECTF* out_rect); diff --git a/fpdfsdk/fpdf_annot.cpp b/fpdfsdk/fpdf_annot.cpp index 2ab0bca454..ccc7596401 100644 --- a/fpdfsdk/fpdf_annot.cpp +++ b/fpdfsdk/fpdf_annot.cpp @@ -194,6 +194,51 @@ void UpdateContentStream(CPDF_Form* pForm, CPDF_Stream* pStream) { pStream->SetDataAndRemoveFilter(&buf); } +void SetQuadPointsAtIndex(CPDF_Array* array, + size_t quad_index, + const FS_QUADPOINTSF* quad_points) { + ASSERT(array); + ASSERT(quad_points); + ASSERT(IsValidQuadPointsIndex(array, quad_index)); + + size_t nIndex = quad_index * 8; + array->SetNewAt<CPDF_Number>(nIndex, quad_points->x1); + array->SetNewAt<CPDF_Number>(++nIndex, quad_points->y1); + array->SetNewAt<CPDF_Number>(++nIndex, quad_points->x2); + array->SetNewAt<CPDF_Number>(++nIndex, quad_points->y2); + array->SetNewAt<CPDF_Number>(++nIndex, quad_points->x3); + array->SetNewAt<CPDF_Number>(++nIndex, quad_points->y3); + array->SetNewAt<CPDF_Number>(++nIndex, quad_points->x4); + array->SetNewAt<CPDF_Number>(++nIndex, quad_points->y4); +} + +void AppendQuadPoints(CPDF_Array* array, const FS_QUADPOINTSF* quad_points) { + ASSERT(quad_points); + ASSERT(array); + + array->AddNew<CPDF_Number>(quad_points->x1); + array->AddNew<CPDF_Number>(quad_points->y1); + array->AddNew<CPDF_Number>(quad_points->x2); + array->AddNew<CPDF_Number>(quad_points->y2); + array->AddNew<CPDF_Number>(quad_points->x3); + array->AddNew<CPDF_Number>(quad_points->y3); + array->AddNew<CPDF_Number>(quad_points->x4); + array->AddNew<CPDF_Number>(quad_points->y4); +} + +void UpdateBBox(const CPDF_Dictionary* annot_dict) { + // Update BBox entry in appearance stream based on the bounding rectangle + // of the annotation's quadpoints. + CPDF_Stream* pStream = + FPDFDOC_GetAnnotAP(annot_dict, CPDF_Annot::AppearanceMode::Normal); + if (pStream) { + CFX_FloatRect boundingRect = + CPDF_Annot::BoundingRectFromQuadPoints(annot_dict); + if (boundingRect.Contains(pStream->GetDict()->GetRectFor("BBox"))) + pStream->GetDict()->SetRectFor("BBox", boundingRect); + } +} + } // namespace FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV @@ -582,42 +627,35 @@ FPDFAnnot_HasAttachmentPoints(FPDF_ANNOTATION annot) { FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_SetAttachmentPoints(FPDF_ANNOTATION annot, + size_t quad_index, const FS_QUADPOINTSF* quad_points) { if (!FPDFAnnot_HasAttachmentPoints(annot) || !quad_points) return false; CPDF_Dictionary* pAnnotDict = CPDFAnnotContextFromFPDFAnnotation(annot)->GetAnnotDict(); - if (!pAnnotDict) + CPDF_Array* pQuadPointsArray = GetQuadPointsArrayFromDictionary(pAnnotDict); + if (!IsValidQuadPointsIndex(pQuadPointsArray, quad_index)) return false; - // Update the "QuadPoints" entry in the annotation dictionary. - CPDF_Array* pQuadPoints = pAnnotDict->GetArrayFor("QuadPoints"); - if (pQuadPoints) - pQuadPoints->Clear(); - else - pQuadPoints = pAnnotDict->SetNewFor<CPDF_Array>("QuadPoints"); - - pQuadPoints->AddNew<CPDF_Number>(quad_points->x1); - pQuadPoints->AddNew<CPDF_Number>(quad_points->y1); - pQuadPoints->AddNew<CPDF_Number>(quad_points->x2); - pQuadPoints->AddNew<CPDF_Number>(quad_points->y2); - pQuadPoints->AddNew<CPDF_Number>(quad_points->x3); - pQuadPoints->AddNew<CPDF_Number>(quad_points->y3); - pQuadPoints->AddNew<CPDF_Number>(quad_points->x4); - pQuadPoints->AddNew<CPDF_Number>(quad_points->y4); - - // If the annotation's appearance stream is defined, and the new quadpoints - // defines a bigger bounding box than the appearance stream currently - // specifies, then update the "BBox" entry in the AP dictionary too, since it - // comes from annotation dictionary's "QuadPoints" entry. - CPDF_Stream* pStream = - FPDFDOC_GetAnnotAP(pAnnotDict, CPDF_Annot::AppearanceMode::Normal); - if (pStream) { - CFX_FloatRect newRect = CPDF_Annot::BoundingRectFromQuadPoints(pAnnotDict); - if (newRect.Contains(pStream->GetDict()->GetRectFor("BBox"))) - pStream->GetDict()->SetRectFor("BBox", newRect); - } + SetQuadPointsAtIndex(pQuadPointsArray, quad_index, quad_points); + UpdateBBox(pAnnotDict); + return true; +} + +FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV +FPDFAnnot_AppendAttachmentPoints(FPDF_ANNOTATION annot, + const FS_QUADPOINTSF* quad_points) { + if (!FPDFAnnot_HasAttachmentPoints(annot) || !quad_points) + return false; + + CPDF_Dictionary* pAnnotDict = + CPDFAnnotContextFromFPDFAnnotation(annot)->GetAnnotDict(); + CPDF_Array* pQuadPointsArray = GetQuadPointsArrayFromDictionary(pAnnotDict); + if (!pQuadPointsArray) + pQuadPointsArray = AddQuadPointsArrayToDictionary(pAnnotDict); + AppendQuadPoints(pQuadPointsArray, quad_points); + UpdateBBox(pAnnotDict); return true; } @@ -634,13 +672,21 @@ FPDFAnnot_CountAttachmentPoints(FPDF_ANNOTATION annot) { FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_GetAttachmentPoints(FPDF_ANNOTATION annot, + size_t quad_index, FS_QUADPOINTSF* quad_points) { if (!FPDFAnnot_HasAttachmentPoints(annot) || !quad_points) return false; - return GetQuadPointsFromDictionary( - CPDFAnnotContextFromFPDFAnnotation(annot)->GetAnnotDict(), 0, - quad_points); + CPDF_Dictionary* pAnnotDict = + CPDFAnnotContextFromFPDFAnnotation(annot)->GetAnnotDict(); + if (!pAnnotDict) + return false; + + const CPDF_Array* pArray = GetQuadPointsArrayFromDictionary(pAnnotDict); + if (!pArray) + return false; + + return GetQuadPointsAtIndex(pArray, quad_index, quad_points); } FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_SetRect(FPDF_ANNOTATION annot, diff --git a/fpdfsdk/fpdf_annot_embeddertest.cpp b/fpdfsdk/fpdf_annot_embeddertest.cpp index b97193db46..9d5c5548b6 100644 --- a/fpdfsdk/fpdf_annot_embeddertest.cpp +++ b/fpdfsdk/fpdf_annot_embeddertest.cpp @@ -134,7 +134,7 @@ TEST_F(FPDFAnnotEmbeddertest, ExtractHighlightLongContent) { // Check that the quadpoints are correct. FS_QUADPOINTSF quadpoints; - ASSERT_TRUE(FPDFAnnot_GetAttachmentPoints(annot.get(), &quadpoints)); + ASSERT_TRUE(FPDFAnnot_GetAttachmentPoints(annot.get(), 0, &quadpoints)); EXPECT_EQ(115.802643f, quadpoints.x1); EXPECT_EQ(718.913940f, quadpoints.y1); EXPECT_EQ(157.211182f, quadpoints.x4); @@ -303,7 +303,7 @@ TEST_F(FPDFAnnotEmbeddertest, AddAndSaveUnderlineAnnotation) { std::unique_ptr<void, FPDFAnnotationDeleter> annot( FPDFPage_GetAnnot(page, 0)); ASSERT_TRUE(annot); - ASSERT_TRUE(FPDFAnnot_GetAttachmentPoints(annot.get(), &quadpoints)); + ASSERT_TRUE(FPDFAnnot_GetAttachmentPoints(annot.get(), 0, &quadpoints)); EXPECT_EQ(115.802643f, quadpoints.x1); EXPECT_EQ(718.913940f, quadpoints.y1); EXPECT_EQ(157.211182f, quadpoints.x4); @@ -317,7 +317,7 @@ TEST_F(FPDFAnnotEmbeddertest, AddAndSaveUnderlineAnnotation) { ASSERT_TRUE(annot); quadpoints.x1 = 140.802643f; quadpoints.x3 = 140.802643f; - ASSERT_TRUE(FPDFAnnot_SetAttachmentPoints(annot.get(), &quadpoints)); + ASSERT_TRUE(FPDFAnnot_AppendAttachmentPoints(annot.get(), &quadpoints)); } // Save the document, closing the page and document. @@ -343,7 +343,7 @@ TEST_F(FPDFAnnotEmbeddertest, AddAndSaveUnderlineAnnotation) { EXPECT_EQ(FPDF_ANNOT_UNDERLINE, FPDFAnnot_GetSubtype(new_annot.get())); FS_QUADPOINTSF new_quadpoints; ASSERT_TRUE( - FPDFAnnot_GetAttachmentPoints(new_annot.get(), &new_quadpoints)); + FPDFAnnot_GetAttachmentPoints(new_annot.get(), 0, &new_quadpoints)); EXPECT_NEAR(quadpoints.x1, new_quadpoints.x1, 0.001f); EXPECT_NEAR(quadpoints.y1, new_quadpoints.y1, 0.001f); EXPECT_NEAR(quadpoints.x4, new_quadpoints.x4, 0.001f); @@ -354,6 +354,91 @@ TEST_F(FPDFAnnotEmbeddertest, AddAndSaveUnderlineAnnotation) { CloseSavedDocument(); } +TEST_F(FPDFAnnotEmbeddertest, GetAndSetQuadPoints) { + // Open a file with four annotations and load its first page. + ASSERT_TRUE(OpenDocument("annotation_highlight_square_with_ap.pdf")); + FPDF_PAGE page = LoadPage(0); + ASSERT_TRUE(page); + EXPECT_EQ(4, FPDFPage_GetAnnotCount(page)); + + // Retrieve the highlight annotation. + FPDF_ANNOTATION annot = FPDFPage_GetAnnot(page, 0); + ASSERT_TRUE(annot); + ASSERT_EQ(FPDF_ANNOT_HIGHLIGHT, FPDFAnnot_GetSubtype(annot)); + + FS_QUADPOINTSF quadpoints; + ASSERT_TRUE(FPDFAnnot_GetAttachmentPoints(annot, 0, &quadpoints)); + + { + // Verify the current one set of quadpoints. + ASSERT_EQ(1u, FPDFAnnot_CountAttachmentPoints(annot)); + + EXPECT_NEAR(72.0000f, quadpoints.x1, 0.001f); + EXPECT_NEAR(720.792f, quadpoints.y1, 0.001f); + EXPECT_NEAR(132.055f, quadpoints.x4, 0.001f); + EXPECT_NEAR(704.796f, quadpoints.y4, 0.001f); + } + + { + // Update the quadpoints. + FS_QUADPOINTSF new_quadpoints = quadpoints; + new_quadpoints.y1 -= 20.f; + new_quadpoints.y2 -= 20.f; + new_quadpoints.y3 -= 20.f; + new_quadpoints.y4 -= 20.f; + ASSERT_TRUE(FPDFAnnot_SetAttachmentPoints(annot, 0, &new_quadpoints)); + + // Verify added quadpoint set + ASSERT_EQ(1u, FPDFAnnot_CountAttachmentPoints(annot)); + ASSERT_TRUE(FPDFAnnot_GetAttachmentPoints(annot, 0, &quadpoints)); + EXPECT_NEAR(new_quadpoints.x1, quadpoints.x1, 0.001f); + EXPECT_NEAR(new_quadpoints.y1, quadpoints.y1, 0.001f); + EXPECT_NEAR(new_quadpoints.x4, quadpoints.x4, 0.001f); + EXPECT_NEAR(new_quadpoints.y4, quadpoints.y4, 0.001f); + } + + { + // Append a new set of quadpoints. + FS_QUADPOINTSF new_quadpoints = quadpoints; + new_quadpoints.y1 += 20.f; + new_quadpoints.y2 += 20.f; + new_quadpoints.y3 += 20.f; + new_quadpoints.y4 += 20.f; + ASSERT_TRUE(FPDFAnnot_AppendAttachmentPoints(annot, &new_quadpoints)); + + // Verify added quadpoint set + ASSERT_EQ(2u, FPDFAnnot_CountAttachmentPoints(annot)); + ASSERT_TRUE(FPDFAnnot_GetAttachmentPoints(annot, 1, &quadpoints)); + EXPECT_NEAR(new_quadpoints.x1, quadpoints.x1, 0.001f); + EXPECT_NEAR(new_quadpoints.y1, quadpoints.y1, 0.001f); + EXPECT_NEAR(new_quadpoints.x4, quadpoints.x4, 0.001f); + EXPECT_NEAR(new_quadpoints.y4, quadpoints.y4, 0.001f); + } + + { + // Setting and getting quadpoints at out-of-bound index should fail + EXPECT_FALSE(FPDFAnnot_SetAttachmentPoints(annot, 300000, &quadpoints)); + EXPECT_FALSE(FPDFAnnot_GetAttachmentPoints(annot, 300000, &quadpoints)); + } + + FPDFPage_CloseAnnot(annot); + + // Retrieve the square annotation + FPDF_ANNOTATION squareAnnot = FPDFPage_GetAnnot(page, 2); + + { + // Check that attempting to set its quadpoints would fail + ASSERT_TRUE(squareAnnot); + EXPECT_EQ(FPDF_ANNOT_SQUARE, FPDFAnnot_GetSubtype(squareAnnot)); + EXPECT_EQ(0u, FPDFAnnot_CountAttachmentPoints(squareAnnot)); + EXPECT_FALSE(FPDFAnnot_SetAttachmentPoints(squareAnnot, 0, &quadpoints)); + } + + FPDFPage_CloseAnnot(squareAnnot); + + UnloadPage(page); +} + TEST_F(FPDFAnnotEmbeddertest, ModifyRectQuadpointsWithAP) { #if _FX_PLATFORM_ == _FX_PLATFORM_APPLE_ const char md5_original[] = "63af8432fab95a67cdebb7cd0e514941"; @@ -398,7 +483,7 @@ TEST_F(FPDFAnnotEmbeddertest, ModifyRectQuadpointsWithAP) { // Verify its attachment points. FS_QUADPOINTSF quadpoints; - ASSERT_TRUE(FPDFAnnot_GetAttachmentPoints(annot.get(), &quadpoints)); + ASSERT_TRUE(FPDFAnnot_GetAttachmentPoints(annot.get(), 0, &quadpoints)); EXPECT_NEAR(72.0000f, quadpoints.x1, 0.001f); EXPECT_NEAR(720.792f, quadpoints.y1, 0.001f); EXPECT_NEAR(132.055f, quadpoints.x4, 0.001f); @@ -409,9 +494,9 @@ TEST_F(FPDFAnnotEmbeddertest, ModifyRectQuadpointsWithAP) { quadpoints.x2 -= 50.f; quadpoints.x3 -= 50.f; quadpoints.x4 -= 50.f; - ASSERT_TRUE(FPDFAnnot_SetAttachmentPoints(annot.get(), &quadpoints)); + ASSERT_TRUE(FPDFAnnot_SetAttachmentPoints(annot.get(), 0, &quadpoints)); FS_QUADPOINTSF new_quadpoints; - ASSERT_TRUE(FPDFAnnot_GetAttachmentPoints(annot.get(), &new_quadpoints)); + ASSERT_TRUE(FPDFAnnot_GetAttachmentPoints(annot.get(), 0, &new_quadpoints)); EXPECT_EQ(quadpoints.x1, new_quadpoints.x1); EXPECT_EQ(quadpoints.y1, new_quadpoints.y1); EXPECT_EQ(quadpoints.x4, new_quadpoints.x4); diff --git a/fpdfsdk/fpdf_doc.cpp b/fpdfsdk/fpdf_doc.cpp index d8be12066a..54718a9409 100644 --- a/fpdfsdk/fpdf_doc.cpp +++ b/fpdfsdk/fpdf_doc.cpp @@ -12,6 +12,7 @@ #include "core/fpdfapi/page/cpdf_page.h" #include "core/fpdfapi/parser/cpdf_array.h" #include "core/fpdfapi/parser/cpdf_document.h" +#include "core/fpdfapi/parser/cpdf_number.h" #include "core/fpdfdoc/cpdf_bookmark.h" #include "core/fpdfdoc/cpdf_bookmarktree.h" #include "core/fpdfdoc/cpdf_dest.h" @@ -390,9 +391,17 @@ FPDFLink_GetQuadPoints(FPDF_LINK link_annot, FS_QUADPOINTSF* quad_points) { if (!quad_points || quad_index < 0) return false; - return GetQuadPointsFromDictionary(CPDFDictionaryFromFPDFLink(link_annot), - static_cast<size_t>(quad_index), - quad_points); + + CPDF_Dictionary* pLinkDict = CPDFDictionaryFromFPDFLink(link_annot); + if (!pLinkDict) + return false; + + const CPDF_Array* pArray = GetQuadPointsArrayFromDictionary(pLinkDict); + if (!pArray) + return false; + + return GetQuadPointsAtIndex(pArray, static_cast<size_t>(quad_index), + quad_points); } FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_GetMetaText(FPDF_DOCUMENT document, diff --git a/fpdfsdk/fpdf_view_c_api_test.c b/fpdfsdk/fpdf_view_c_api_test.c index 1942b73957..fbfa71cf70 100644 --- a/fpdfsdk/fpdf_view_c_api_test.c +++ b/fpdfsdk/fpdf_view_c_api_test.c @@ -55,6 +55,7 @@ int CheckPDFiumCApi() { CHK(FPDFAnnot_GetColor); CHK(FPDFAnnot_HasAttachmentPoints); CHK(FPDFAnnot_SetAttachmentPoints); + CHK(FPDFAnnot_AppendAttachmentPoints); CHK(FPDFAnnot_CountAttachmentPoints); CHK(FPDFAnnot_GetAttachmentPoints); CHK(FPDFAnnot_SetRect); diff --git a/public/fpdf_annot.h b/public/fpdf_annot.h index a84c4f982a..8e9b93e12d 100644 --- a/public/fpdf_annot.h +++ b/public/fpdf_annot.h @@ -285,7 +285,7 @@ FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_GetColor(FPDF_ANNOTATION annot, // Experimental API. // Check if the annotation is of a type that has attachment points -// (i.e. quadpoints). Quadpoints are the vertices of the rectange that +// (i.e. quadpoints). Quadpoints are the vertices of the rectangle that // encompasses the texts affected by the annotation. They provide the // coordinates in the page where the annotation is attached. Only text markup // annotations (i.e. highlight, strikeout, squiggly, and underline) and link @@ -299,20 +299,38 @@ FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_HasAttachmentPoints(FPDF_ANNOTATION annot); // Experimental API. -// Set the attachment points (i.e. quadpoints) of an annotation. If the -// annotation's appearance stream is defined and this annotation is of a type -// with quadpoints, then update the bounding box too if the new quadpoints +// Replace the attachment points (i.e. quadpoints) set of an annotation at +// |quad_index|. This index needs to be within the result of +// FPDFAnnot_CountAttachmentPoints(). +// If the annotation's appearance stream is defined and this annotation is of a +// type with quadpoints, then update the bounding box too if the new quadpoints // define a bigger one. // // annot - handle to an annotation. +// quad_index - index of the set of quadpoints. // quad_points - the quadpoints to be set. // // Returns true if successful. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_SetAttachmentPoints(FPDF_ANNOTATION annot, + size_t quad_index, const FS_QUADPOINTSF* quad_points); // Experimental API. +// Append to the list of attachment points (i.e. quadpoints) of an annotation. +// If the annotation's appearance stream is defined and this annotation is of a +// type with quadpoints, then update the bounding box too if the new quadpoints +// define a bigger one. +// +// annot - handle to an annotation. +// quad_points - the quadpoints to be set. +// +// Returns true if successful. +FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV +FPDFAnnot_AppendAttachmentPoints(FPDF_ANNOTATION annot, + const FS_QUADPOINTSF* quad_points); + +// Experimental API. // Get the number of sets of quadpoints of an annotation. // // annot - handle to an annotation. @@ -325,11 +343,13 @@ FPDFAnnot_CountAttachmentPoints(FPDF_ANNOTATION annot); // Get the attachment points (i.e. quadpoints) of an annotation. // // annot - handle to an annotation. +// quad_index - index of the set of quadpoints. // quad_points - receives the quadpoints; must not be NULL. // // Returns true if successful. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_GetAttachmentPoints(FPDF_ANNOTATION annot, + size_t quad_index, FS_QUADPOINTSF* quad_points); // Experimental API. diff --git a/samples/pdfium_test_write_helper.cc b/samples/pdfium_test_write_helper.cc index 5a2e0f66ce..d061252e07 100644 --- a/samples/pdfium_test_write_helper.cc +++ b/samples/pdfium_test_write_helper.cc @@ -315,15 +315,22 @@ void WriteAnnot(FPDF_PAGE page, const char* pdf_name, int num) { // Retrieve the annotation's quadpoints if it is a markup annotation. if (FPDFAnnot_HasAttachmentPoints(annot.get())) { - FS_QUADPOINTSF quadpoints; - if (FPDFAnnot_GetAttachmentPoints(annot.get(), &quadpoints)) { - fprintf(fp, - "Quadpoints: (%.3f, %.3f), (%.3f, %.3f), (%.3f, %.3f), (%.3f, " - "%.3f)\n", - quadpoints.x1, quadpoints.y1, quadpoints.x2, quadpoints.y2, - quadpoints.x3, quadpoints.y3, quadpoints.x4, quadpoints.y4); - } else { - fprintf(fp, "Failed to retrieve quadpoints.\n"); + size_t qp_count = FPDFAnnot_CountAttachmentPoints(annot.get()); + fprintf(fp, "Number of quadpoints sets: %zu\n", qp_count); + + // Iterate through all quadpoints of the current annotation + for (size_t j = 0; j < qp_count; ++j) { + FS_QUADPOINTSF quadpoints; + if (FPDFAnnot_GetAttachmentPoints(annot.get(), j, &quadpoints)) { + fprintf(fp, + "Quadpoints set #%zu: (%.3f, %.3f), (%.3f, %.3f), " + "(%.3f, %.3f), (%.3f, %.3f)\n", + j + 1, quadpoints.x1, quadpoints.y1, quadpoints.x2, + quadpoints.y2, quadpoints.x3, quadpoints.y3, quadpoints.x4, + quadpoints.y4); + } else { + fprintf(fp, "Failed to retrieve quadpoints set #%zu.\n", j + 1); + } } } |