summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJane Liu <janeliulwq@google.com>2017-07-11 13:47:37 -0400
committerChromium commit bot <commit-bot@chromium.org>2017-07-11 18:09:41 +0000
commit7a9a38bd1c41f0f909534e56789a22d57b1a2663 (patch)
tree15c8cc22d5988dcf89f1bbafe7959001311a1449
parenta8fbdc45210856e3130977c188b0efd468031e2a (diff)
downloadpdfium-7a9a38bd1c41f0f909534e56789a22d57b1a2663.tar.xz
Added API for removing objects from annotations
Bug=pdfium:737 Change-Id: Ia485219b9288b9fe7e1ae226035b37dde2bc3abd Reviewed-on: https://pdfium-review.googlesource.com/7213 Commit-Queue: Jane Liu <janeliulwq@google.com> Commit-Queue: dsinclair <dsinclair@chromium.org> Reviewed-by: dsinclair <dsinclair@chromium.org> Reviewed-by: Lei Zhang <thestig@chromium.org>
-rw-r--r--fpdfsdk/fpdfannot.cpp65
-rw-r--r--fpdfsdk/fpdfannot_embeddertest.cpp102
-rw-r--r--fpdfsdk/fpdfview_c_api_test.c2
-rw-r--r--public/fpdf_annot.h21
4 files changed, 135 insertions, 55 deletions
diff --git a/fpdfsdk/fpdfannot.cpp b/fpdfsdk/fpdfannot.cpp
index b8043b0a66..faa4f4c8fb 100644
--- a/fpdfsdk/fpdfannot.cpp
+++ b/fpdfsdk/fpdfannot.cpp
@@ -176,6 +176,15 @@ CFX_ByteString CFXByteStringFromFPDFWideString(FPDF_WIDESTRING text) {
return CFX_WideString::FromUTF16LE(text, CFX_WideString::WStringLength(text))
.UTF8Encode();
}
+void UpdateContentStream(CPDF_Form* pForm, CPDF_Stream* pStream) {
+ ASSERT(pForm);
+ ASSERT(pStream);
+
+ CPDF_PageContentGenerator generator(pForm);
+ std::ostringstream buf;
+ generator.ProcessPageObjects(&buf);
+ pStream->SetData(&buf);
+}
} // namespace
@@ -266,6 +275,12 @@ FPDFAnnot_GetSubtype(FPDF_ANNOTATION annot) {
CPDF_Annot::StringToAnnotSubtype(pAnnotDict->GetStringFor("Subtype")));
}
+DLLEXPORT FPDF_BOOL STDCALL
+FPDFAnnot_IsObjectSupportedSubtype(FPDF_ANNOTATION_SUBTYPE subtype) {
+ // The supported subtypes must also be communicated in the user doc.
+ return subtype == FPDF_ANNOT_INK || subtype == FPDF_ANNOT_STAMP;
+}
+
DLLEXPORT FPDF_BOOL STDCALL FPDFAnnot_UpdateObject(FPDF_ANNOTATION annot,
FPDF_PAGEOBJECT obj) {
CPDF_AnnotContext* pAnnot = CPDFAnnotContextFromFPDFAnnotation(annot);
@@ -274,8 +289,7 @@ DLLEXPORT FPDF_BOOL STDCALL FPDFAnnot_UpdateObject(FPDF_ANNOTATION annot,
return false;
// Check that the annotation type is supported by this method.
- FPDF_ANNOTATION_SUBTYPE subtype = FPDFAnnot_GetSubtype(annot);
- if (subtype != FPDF_ANNOT_INK && subtype != FPDF_ANNOT_STAMP)
+ if (!FPDFAnnot_IsObjectSupportedSubtype(FPDFAnnot_GetSubtype(annot)))
return false;
// Check that the annotation already has an appearance stream, since an
@@ -286,7 +300,8 @@ DLLEXPORT FPDF_BOOL STDCALL FPDFAnnot_UpdateObject(FPDF_ANNOTATION annot,
return false;
// Check that the object is already in this annotation's object list.
- CPDF_PageObjectList* pObjList = pAnnot->GetForm()->GetPageObjectList();
+ CPDF_Form* pForm = pAnnot->GetForm();
+ CPDF_PageObjectList* pObjList = pForm->GetPageObjectList();
auto it =
std::find_if(pObjList->begin(), pObjList->end(),
[pObj](const std::unique_ptr<CPDF_PageObject>& candidate) {
@@ -296,11 +311,7 @@ DLLEXPORT FPDF_BOOL STDCALL FPDFAnnot_UpdateObject(FPDF_ANNOTATION annot,
return false;
// Update the content stream data in the annotation's AP stream.
- CPDF_PageContentGenerator generator(pAnnot->GetForm());
- std::ostringstream buf;
- generator.ProcessPageObjects(&buf);
- pStream->SetData(reinterpret_cast<const uint8_t*>(buf.str().c_str()),
- buf.tellp());
+ UpdateContentStream(pForm, pStream);
return true;
}
@@ -317,8 +328,7 @@ DLLEXPORT FPDF_BOOL STDCALL FPDFAnnot_AppendObject(FPDF_ANNOTATION annot,
return false;
// Check that the annotation type is supported by this method.
- FPDF_ANNOTATION_SUBTYPE subtype = FPDFAnnot_GetSubtype(annot);
- if (subtype != FPDF_ANNOT_INK && subtype != FPDF_ANNOT_STAMP)
+ if (!FPDFAnnot_IsObjectSupportedSubtype(FPDFAnnot_GetSubtype(annot)))
return false;
// If the annotation does not have an AP stream yet, generate and set it.
@@ -343,13 +353,12 @@ DLLEXPORT FPDF_BOOL STDCALL FPDFAnnot_AppendObject(FPDF_ANNOTATION annot,
if (!pAnnot->HasForm())
pAnnot->SetForm(pStream);
- CPDF_Form* pForm = pAnnot->GetForm();
-
// Check that the object did not come from the same annotation. If this check
// succeeds, then it is assumed that the object came from
// FPDFPageObj_CreateNew{Path|Rect}() or FPDFPageObj_New{Text|Image}Obj().
// Note that an object that came from a different annotation must not be
// passed here, since an object cannot belong to more than one annotation.
+ CPDF_Form* pForm = pAnnot->GetForm();
CPDF_PageObjectList* pObjList = pForm->GetPageObjectList();
auto it =
std::find_if(pObjList->begin(), pObjList->end(),
@@ -364,11 +373,7 @@ DLLEXPORT FPDF_BOOL STDCALL FPDFAnnot_AppendObject(FPDF_ANNOTATION annot,
pObjList->push_back(std::move(pPageObjHolder));
// Set the content stream data in the annotation's AP stream.
- CPDF_PageContentGenerator generator(pForm);
- std::ostringstream buf;
- generator.ProcessPageObjects(&buf);
- pStream->SetData(reinterpret_cast<const uint8_t*>(buf.str().c_str()),
- buf.tellp());
+ UpdateContentStream(pForm, pStream);
return true;
}
@@ -406,6 +411,32 @@ DLLEXPORT FPDF_PAGEOBJECT STDCALL FPDFAnnot_GetObject(FPDF_ANNOTATION annot,
return pAnnot->GetForm()->GetPageObjectList()->GetPageObjectByIndex(index);
}
+DLLEXPORT FPDF_BOOL STDCALL FPDFAnnot_RemoveObject(FPDF_ANNOTATION annot,
+ int index) {
+ CPDF_AnnotContext* pAnnot = CPDFAnnotContextFromFPDFAnnotation(annot);
+ if (!pAnnot || !pAnnot->GetAnnotDict() || !pAnnot->HasForm() || index < 0)
+ return false;
+
+ // Check that the annotation type is supported by this method.
+ if (!FPDFAnnot_IsObjectSupportedSubtype(FPDFAnnot_GetSubtype(annot)))
+ return false;
+
+ // Check that the annotation already has an appearance stream, since an
+ // existing object is to be deleted.
+ CPDF_Stream* pStream = FPDFDOC_GetAnnotAP(pAnnot->GetAnnotDict(),
+ CPDF_Annot::AppearanceMode::Normal);
+ if (!pStream)
+ return false;
+
+ CPDF_PageObjectList* pObjList = pAnnot->GetForm()->GetPageObjectList();
+ if (static_cast<size_t>(index) >= pObjList->size())
+ return false;
+
+ pObjList->erase(pObjList->begin() + index);
+ UpdateContentStream(pAnnot->GetForm(), pStream);
+ return true;
+}
+
DLLEXPORT FPDF_BOOL STDCALL FPDFAnnot_SetColor(FPDF_ANNOTATION annot,
FPDFANNOT_COLORTYPE type,
unsigned int R,
diff --git a/fpdfsdk/fpdfannot_embeddertest.cpp b/fpdfsdk/fpdfannot_embeddertest.cpp
index c2bd82ae72..c042b764a2 100644
--- a/fpdfsdk/fpdfannot_embeddertest.cpp
+++ b/fpdfsdk/fpdfannot_embeddertest.cpp
@@ -468,17 +468,20 @@ TEST_F(FPDFAnnotEmbeddertest, RemoveAnnotation) {
TEST_F(FPDFAnnotEmbeddertest, AddAndModifyPath) {
#if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
- const char md5[] = "c35408717759562d1f8bf33d317483d2";
- const char md5_2[] = "cf3cea74bd46497520ff6c4d1ea228c8";
- const char md5_3[] = "ee5372b31fede117fc83b9384598aa25";
+ const char md5_original[] = "c35408717759562d1f8bf33d317483d2";
+ const char md5_modified_path[] = "cf3cea74bd46497520ff6c4d1ea228c8";
+ const char md5_two_paths[] = "e8994452fc4385337bae5522354e10ff";
+ const char md5_new_annot[] = "ee5372b31fede117fc83b9384598aa25";
#elif _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_
- const char md5[] = "4f64add0190ede63f7bb9eb1e2e83edb";
- const char md5_2[] = "681f0d0738dded0722e146f6c219bfac";
- const char md5_3[] = "262187984451bae2fe826067d68623ff";
+ const char md5_original[] = "4f64add0190ede63f7bb9eb1e2e83edb";
+ const char md5_modified_path[] = "681f0d0738dded0722e146f6c219bfac";
+ const char md5_two_paths[] = "67c7e90fc3b64e20f6b69a1744f7f4f0";
+ const char md5_new_annot[] = "262187984451bae2fe826067d68623ff";
#else
- const char md5[] = "02e1c6adff8fee4aeabd91c2c2e4be43";
- const char md5_2[] = "87a78cbacd8509b961a67be56b5665a2";
- const char md5_3[] = "c95de7a9a1f61faca03d953961a319b9";
+ const char md5_original[] = "02e1c6adff8fee4aeabd91c2c2e4be43";
+ const char md5_modified_path[] = "87a78cbacd8509b961a67be56b5665a2";
+ const char md5_two_paths[] = "76e985c18b73ceacf409f77f978176d4";
+ const char md5_new_annot[] = "c95de7a9a1f61faca03d953961a319b9";
#endif
// Open a file with two annotations and load its first page.
@@ -489,7 +492,7 @@ TEST_F(FPDFAnnotEmbeddertest, AddAndModifyPath) {
// Check that the page renders correctly.
FPDF_BITMAP bitmap = RenderPageWithFlags(page, form_handle_, FPDF_ANNOT);
- CompareBitmap(bitmap, 595, 842, md5);
+ CompareBitmap(bitmap, 595, 842, md5_original);
FPDFBitmap_Destroy(bitmap);
// Retrieve the stamp annotation which has its AP stream already defined.
@@ -507,11 +510,34 @@ TEST_F(FPDFAnnotEmbeddertest, AddAndModifyPath) {
// Modify the color of the path object.
EXPECT_TRUE(FPDFPath_SetStrokeColor(path, 0, 0, 0, 255));
EXPECT_TRUE(FPDFAnnot_UpdateObject(annot, path));
- FPDFPage_CloseAnnot(annot);
// Check that the page with the modified annotation renders correctly.
bitmap = RenderPageWithFlags(page, form_handle_, FPDF_ANNOT);
- CompareBitmap(bitmap, 595, 842, md5_2);
+ CompareBitmap(bitmap, 595, 842, md5_modified_path);
+ FPDFBitmap_Destroy(bitmap);
+
+ // Add a second path object to the same annotation.
+ FPDF_PAGEOBJECT dot = FPDFPageObj_CreateNewPath(7, 84);
+ EXPECT_TRUE(FPDFPath_BezierTo(dot, 9, 86, 10, 87, 11, 88));
+ EXPECT_TRUE(FPDFPath_SetStrokeColor(dot, 255, 0, 0, 100));
+ EXPECT_TRUE(FPDFPath_SetStrokeWidth(dot, 14));
+ EXPECT_TRUE(FPDFPath_SetDrawMode(dot, 0, 1));
+ EXPECT_TRUE(FPDFAnnot_AppendObject(annot, dot));
+ EXPECT_EQ(2, FPDFAnnot_GetObjectCount(annot));
+
+ // Check that the page with an annotation with two paths renders correctly.
+ bitmap = RenderPageWithFlags(page, form_handle_, FPDF_ANNOT);
+ CompareBitmap(bitmap, 595, 842, md5_two_paths);
+ FPDFBitmap_Destroy(bitmap);
+
+ // Delete the newly added path object.
+ EXPECT_TRUE(FPDFAnnot_RemoveObject(annot, 1));
+ EXPECT_EQ(1, FPDFAnnot_GetObjectCount(annot));
+ FPDFPage_CloseAnnot(annot);
+
+ // Check that the page renders the same as before.
+ bitmap = RenderPageWithFlags(page, form_handle_, FPDF_ANNOT);
+ CompareBitmap(bitmap, 595, 842, md5_modified_path);
FPDFBitmap_Destroy(bitmap);
// Create another stamp annotation and set its annotation rectangle.
@@ -549,7 +575,7 @@ TEST_F(FPDFAnnotEmbeddertest, AddAndModifyPath) {
FPDF_ClosePage(page);
// Open the saved document.
- TestSaved(595, 842, md5_3);
+ TestSaved(595, 842, md5_new_annot);
// Check that the document has a correct count of annotations and objects.
EXPECT_EQ(3, FPDFPage_GetAnnotCount(m_SavedPage));
@@ -620,17 +646,17 @@ TEST_F(FPDFAnnotEmbeddertest, ModifyAnnotationFlags) {
TEST_F(FPDFAnnotEmbeddertest, AddAndModifyImage) {
#if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
- const char md5[] = "c35408717759562d1f8bf33d317483d2";
- const char md5_2[] = "ff012f5697436dfcaec25b32d1333596";
- const char md5_3[] = "86cf8cb2755a7a2046a543e66d9c1e61";
+ const char md5_original[] = "c35408717759562d1f8bf33d317483d2";
+ const char md5_new_image[] = "ff012f5697436dfcaec25b32d1333596";
+ const char md5_modified_image[] = "86cf8cb2755a7a2046a543e66d9c1e61";
#elif _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_
- const char md5[] = "4f64add0190ede63f7bb9eb1e2e83edb";
- const char md5_2[] = "6fb176c20996cc554d0210d8c8b6138f";
- const char md5_3[] = "546959714dfb0dcd7e7b00259e8d178c";
+ const char md5_original[] = "4f64add0190ede63f7bb9eb1e2e83edb";
+ const char md5_new_image[] = "6fb176c20996cc554d0210d8c8b6138f";
+ const char md5_modified_image[] = "546959714dfb0dcd7e7b00259e8d178c";
#else
- const char md5[] = "02e1c6adff8fee4aeabd91c2c2e4be43";
- const char md5_2[] = "e7658232abd8977cdc3367dd02aee04a";
- const char md5_3[] = "f393432b9a9b452ea69022f46c8b3f75";
+ const char md5_original[] = "02e1c6adff8fee4aeabd91c2c2e4be43";
+ const char md5_new_image[] = "e7658232abd8977cdc3367dd02aee04a";
+ const char md5_modified_image[] = "f393432b9a9b452ea69022f46c8b3f75";
#endif
// Open a file with two annotations and load its first page.
@@ -641,7 +667,7 @@ TEST_F(FPDFAnnotEmbeddertest, AddAndModifyImage) {
// Check that the page renders correctly.
FPDF_BITMAP bitmap = RenderPageWithFlags(page, form_handle_, FPDF_ANNOT);
- CompareBitmap(bitmap, 595, 842, md5);
+ CompareBitmap(bitmap, 595, 842, md5_original);
FPDFBitmap_Destroy(bitmap);
// Create a stamp annotation and set its annotation rectangle.
@@ -670,7 +696,7 @@ TEST_F(FPDFAnnotEmbeddertest, AddAndModifyImage) {
// Check that the page renders correctly with the new image object.
bitmap = RenderPageWithFlags(page, form_handle_, FPDF_ANNOT);
- CompareBitmap(bitmap, 595, 842, md5_2);
+ CompareBitmap(bitmap, 595, 842, md5_new_image);
FPDFBitmap_Destroy(bitmap);
// Retrieve the newly added stamp annotation and its image object.
@@ -691,7 +717,7 @@ TEST_F(FPDFAnnotEmbeddertest, AddAndModifyImage) {
FPDF_ClosePage(page);
// Test that the saved document renders the modified image object correctly.
- TestSaved(595, 842, md5_3);
+ TestSaved(595, 842, md5_modified_image);
FPDFBitmap_Destroy(image_bitmap);
CloseSaved();
@@ -699,17 +725,17 @@ TEST_F(FPDFAnnotEmbeddertest, AddAndModifyImage) {
TEST_F(FPDFAnnotEmbeddertest, AddAndModifyText) {
#if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
- const char md5[] = "c35408717759562d1f8bf33d317483d2";
- const char md5_2[] = "e5680ed048c2cfd9a1d27212cdf41286";
- const char md5_3[] = "79f5cfb0b07caaf936f65f6a7a57ce77";
+ const char md5_original[] = "c35408717759562d1f8bf33d317483d2";
+ const char md5_new_text[] = "e5680ed048c2cfd9a1d27212cdf41286";
+ const char md5_modified_text[] = "79f5cfb0b07caaf936f65f6a7a57ce77";
#elif _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_
- const char md5[] = "4f64add0190ede63f7bb9eb1e2e83edb";
- const char md5_2[] = "998abae4962f8f41e094e7612d8339fc";
- const char md5_3[] = "e89b82ca4589b8f0b45fff42ca3a96a4";
+ const char md5_original[] = "4f64add0190ede63f7bb9eb1e2e83edb";
+ const char md5_new_text[] = "998abae4962f8f41e094e7612d8339fc";
+ const char md5_modified_text[] = "e89b82ca4589b8f0b45fff42ca3a96a4";
#else
- const char md5[] = "02e1c6adff8fee4aeabd91c2c2e4be43";
- const char md5_2[] = "3fbbaec4d846ccf2be89e09daae0273d";
- const char md5_3[] = "2ad0acaf2d8990bcdf48e1d12e6c44ad";
+ const char md5_original[] = "02e1c6adff8fee4aeabd91c2c2e4be43";
+ const char md5_new_text[] = "3fbbaec4d846ccf2be89e09daae0273d";
+ const char md5_modified_text[] = "2ad0acaf2d8990bcdf48e1d12e6c44ad";
#endif
// Open a file with two annotations and load its first page.
@@ -720,7 +746,7 @@ TEST_F(FPDFAnnotEmbeddertest, AddAndModifyText) {
// Check that the page renders correctly.
FPDF_BITMAP bitmap = RenderPageWithFlags(page, form_handle_, FPDF_ANNOT);
- CompareBitmap(bitmap, 595, 842, md5);
+ CompareBitmap(bitmap, 595, 842, md5_original);
FPDFBitmap_Destroy(bitmap);
// Create a stamp annotation and set its annotation rectangle.
@@ -747,7 +773,7 @@ TEST_F(FPDFAnnotEmbeddertest, AddAndModifyText) {
// Check that the page renders correctly with the new text object.
bitmap = RenderPageWithFlags(page, form_handle_, FPDF_ANNOT);
- CompareBitmap(bitmap, 595, 842, md5_2);
+ CompareBitmap(bitmap, 595, 842, md5_new_text);
FPDFBitmap_Destroy(bitmap);
// Retrieve the newly added stamp annotation and its text object.
@@ -766,13 +792,13 @@ TEST_F(FPDFAnnotEmbeddertest, AddAndModifyText) {
// Check that the page renders correctly with the modified text object.
bitmap = RenderPageWithFlags(page, form_handle_, FPDF_ANNOT);
- CompareBitmap(bitmap, 595, 842, md5_3);
+ CompareBitmap(bitmap, 595, 842, md5_modified_text);
FPDFBitmap_Destroy(bitmap);
// Remove the new annotation, and check that the page renders as before.
EXPECT_TRUE(FPDFPage_RemoveAnnot(page, 2));
bitmap = RenderPageWithFlags(page, form_handle_, FPDF_ANNOT);
- CompareBitmap(bitmap, 595, 842, md5);
+ CompareBitmap(bitmap, 595, 842, md5_original);
FPDFBitmap_Destroy(bitmap);
UnloadPage(page);
diff --git a/fpdfsdk/fpdfview_c_api_test.c b/fpdfsdk/fpdfview_c_api_test.c
index e6a58734d2..1c066dd295 100644
--- a/fpdfsdk/fpdfview_c_api_test.c
+++ b/fpdfsdk/fpdfview_c_api_test.c
@@ -42,10 +42,12 @@ int CheckPDFiumCApi() {
CHK(FPDFPage_CloseAnnot);
CHK(FPDFPage_RemoveAnnot);
CHK(FPDFAnnot_GetSubtype);
+ CHK(FPDFAnnot_IsObjectSupportedSubtype);
CHK(FPDFAnnot_UpdateObject);
CHK(FPDFAnnot_AppendObject);
CHK(FPDFAnnot_GetObjectCount);
CHK(FPDFAnnot_GetObject);
+ CHK(FPDFAnnot_RemoveObject);
CHK(FPDFAnnot_SetColor);
CHK(FPDFAnnot_GetColor);
CHK(FPDFAnnot_HasAttachmentPoints);
diff --git a/public/fpdf_annot.h b/public/fpdf_annot.h
index 31779a5cd8..c42b7059dc 100644
--- a/public/fpdf_annot.h
+++ b/public/fpdf_annot.h
@@ -142,6 +142,17 @@ DLLEXPORT FPDF_ANNOTATION_SUBTYPE STDCALL
FPDFAnnot_GetSubtype(FPDF_ANNOTATION annot);
// Experimental API.
+// Check if an annotation subtype is currently supported for object extraction,
+// update, and removal.
+// Currently supported subtypes: ink and stamp.
+//
+// subtype - the subtype to be checked.
+//
+// Returns true if this subtype supported.
+DLLEXPORT FPDF_BOOL STDCALL
+FPDFAnnot_IsObjectSupportedSubtype(FPDF_ANNOTATION_SUBTYPE subtype);
+
+// Experimental API.
// Update |obj| in |annot|. |obj| must be in |annot| already and must have
// been retrieved by FPDFAnnot_GetObject(). Currently, only ink and stamp
// annotations are supported by this API. Also note that only path, image, and
@@ -189,6 +200,16 @@ DLLEXPORT FPDF_PAGEOBJECT STDCALL FPDFAnnot_GetObject(FPDF_ANNOTATION annot,
int index);
// Experimental API.
+// Remove the object in |annot| at |index|.
+//
+// annot - handle to an annotation.
+// index - the index of the object to be removed.
+//
+// Return true if successful.
+DLLEXPORT FPDF_BOOL STDCALL FPDFAnnot_RemoveObject(FPDF_ANNOTATION annot,
+ int index);
+
+// Experimental API.
// Set the color of an annotation. Fails when called on annotations with
// appearance streams already defined; instead use
// FPDFPath_Set{Stroke|Fill}Color().