Create API to remove a parameter from a content mark.

- FPDFPageObjMark_RemoveParam()

Bug: pdfium:1037
Change-Id: I3ec25128795c36ba7f2f72a9d288a7855ecc3180
Reviewed-on: https://pdfium-review.googlesource.com/37770
Commit-Queue: Henrique Nakashima <hnakashima@chromium.org>
Reviewed-by: Lei Zhang <thestig@chromium.org>
diff --git a/fpdfsdk/fpdf_edit_embeddertest.cpp b/fpdfsdk/fpdf_edit_embeddertest.cpp
index 9a03a4d..0c0776f 100644
--- a/fpdfsdk/fpdf_edit_embeddertest.cpp
+++ b/fpdfsdk/fpdf_edit_embeddertest.cpp
@@ -741,6 +741,82 @@
   CloseSavedDocument();
 }
 
+TEST_F(FPDFEditEmbeddertest, RemoveMarkParam) {
+  // Load document with some text.
+  EXPECT_TRUE(OpenDocument("text_in_page_marked.pdf"));
+  FPDF_PAGE page = LoadPage(0);
+  ASSERT_TRUE(page);
+
+  constexpr int kExpectedObjectCount = 19;
+  CheckMarkCounts(page, 1, kExpectedObjectCount, 8, 4, 9, 1);
+
+  // Remove all "Square" content marks parameters.
+  for (int i = 0; i < kExpectedObjectCount; ++i) {
+    FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, i);
+
+    int mark_count = FPDFPageObj_CountMarks(page_object);
+    for (int j = 0; j < mark_count; ++j) {
+      FPDF_PAGEOBJECTMARK mark = FPDFPageObj_GetMark(page_object, j);
+
+      char buffer[256];
+      ASSERT_GT(FPDFPageObjMark_GetName(mark, buffer, sizeof(buffer)), 0u);
+      std::wstring name =
+          GetPlatformWString(reinterpret_cast<unsigned short*>(buffer));
+      if (name == L"Square") {
+        // Show the mark has a "Factor" parameter.
+        int out_value;
+        EXPECT_TRUE(
+            FPDFPageObjMark_GetParamIntValue(mark, "Factor", &out_value));
+
+        // Remove parameter.
+        EXPECT_TRUE(FPDFPageObjMark_RemoveParam(page_object, mark, "Factor"));
+
+        // Verify the "Factor" parameter is gone.
+        EXPECT_FALSE(
+            FPDFPageObjMark_GetParamIntValue(mark, "Factor", &out_value));
+      }
+    }
+  }
+
+  // Save the file.
+  EXPECT_TRUE(FPDFPage_GenerateContent(page));
+  EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
+  UnloadPage(page);
+
+  // Re-open the file and check the "Factor" parameters are still gone.
+  OpenSavedDocument();
+  FPDF_PAGE saved_page = LoadSavedPage(0);
+
+  size_t square_count = 0;
+  for (int i = 0; i < kExpectedObjectCount; ++i) {
+    FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(saved_page, i);
+
+    int mark_count = FPDFPageObj_CountMarks(page_object);
+    for (int j = 0; j < mark_count; ++j) {
+      FPDF_PAGEOBJECTMARK mark = FPDFPageObj_GetMark(page_object, j);
+
+      char buffer[256];
+      ASSERT_GT(FPDFPageObjMark_GetName(mark, buffer, sizeof(buffer)), 0u);
+      std::wstring name =
+          GetPlatformWString(reinterpret_cast<unsigned short*>(buffer));
+      if (name == L"Square") {
+        // Verify the "Factor" parameter is still gone.
+        int out_value;
+        EXPECT_FALSE(
+            FPDFPageObjMark_GetParamIntValue(mark, "Factor", &out_value));
+
+        ++square_count;
+      }
+    }
+  }
+
+  // Verify the parameters are gone, but the marks are not.
+  EXPECT_EQ(4u, square_count);
+
+  CloseSavedPage(saved_page);
+  CloseSavedDocument();
+}
+
 TEST_F(FPDFEditEmbeddertest, MaintainMarkedObjects) {
   // Load document with some text.
   EXPECT_TRUE(OpenDocument("text_in_page_marked.pdf"));
diff --git a/fpdfsdk/fpdf_editpage.cpp b/fpdfsdk/fpdf_editpage.cpp
index 808e330..5a7312d 100644
--- a/fpdfsdk/fpdf_editpage.cpp
+++ b/fpdfsdk/fpdf_editpage.cpp
@@ -99,11 +99,11 @@
   }
 }
 
-const CPDF_Dictionary* GetMarkParamDict(FPDF_PAGEOBJECTMARK mark) {
+CPDF_Dictionary* GetMarkParamDict(FPDF_PAGEOBJECTMARK mark) {
   if (!mark)
     return nullptr;
 
-  const CPDF_ContentMarkItem* pMarkItem =
+  CPDF_ContentMarkItem* pMarkItem =
       CPDFContentMarkItemFromFPDFPageObjectMark(mark);
 
   return pMarkItem->GetParam();
@@ -566,6 +566,26 @@
   return true;
 }
 
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
+FPDFPageObjMark_RemoveParam(FPDF_PAGEOBJECT page_object,
+                            FPDF_PAGEOBJECTMARK mark,
+                            FPDF_BYTESTRING key) {
+  CPDF_PageObject* pPageObj = CPDFPageObjectFromFPDFPageObject(page_object);
+  if (!pPageObj)
+    return false;
+
+  CPDF_Dictionary* pParams = GetMarkParamDict(mark);
+  if (!pParams)
+    return false;
+
+  auto removed = pParams->RemoveFor(key);
+  if (!removed)
+    return false;
+
+  pPageObj->SetDirty(true);
+  return true;
+}
+
 FPDF_EXPORT int FPDF_CALLCONV FPDFPageObj_GetType(FPDF_PAGEOBJECT pageObject) {
   if (!pageObject)
     return FPDF_PAGEOBJ_UNKNOWN;
diff --git a/fpdfsdk/fpdf_view_c_api_test.c b/fpdfsdk/fpdf_view_c_api_test.c
index 96c9bfe..d4c812f 100644
--- a/fpdfsdk/fpdf_view_c_api_test.c
+++ b/fpdfsdk/fpdf_view_c_api_test.c
@@ -144,6 +144,7 @@
     CHK(FPDFPageObjMark_GetParamKey);
     CHK(FPDFPageObjMark_GetParamStringValue);
     CHK(FPDFPageObjMark_GetParamValueType);
+    CHK(FPDFPageObjMark_RemoveParam);
     CHK(FPDFPageObjMark_SetBlobParam);
     CHK(FPDFPageObjMark_SetIntParam);
     CHK(FPDFPageObjMark_SetStringParam);
diff --git a/public/fpdf_edit.h b/public/fpdf_edit.h
index e18f1cd..fdd8c97 100644
--- a/public/fpdf_edit.h
+++ b/public/fpdf_edit.h
@@ -505,6 +505,19 @@
                              void* value,
                              unsigned long value_len);
 
+// Experimental API.
+// Removes a property from a content mark by key.
+//
+//   page_object - handle to the page object with the mark.
+//   mark        - handle to a content mark.
+//   key         - string key of the property.
+//
+// Returns TRUE if the operation succeeded, FALSE otherwise.
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
+FPDFPageObjMark_RemoveParam(FPDF_PAGEOBJECT page_object,
+                            FPDF_PAGEOBJECTMARK mark,
+                            FPDF_BYTESTRING key);
+
 // Load an image from a JPEG image file and then set it into |image_object|.
 //
 //   pages        - pointer to the start of all loaded pages, may be NULL.