Add RemoveTextObjectWithTwoPagesSharingContentStreamAndResources test

Add a test case to demonstrate FPDFPage_RemoveObject() not working
correctly when 2 pages share the same page /Content stream object.

Bug: pdfium:2012
Change-Id: I5fc0f0888d71368c0dd257931e4a1013301f639f
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/105212
Reviewed-by: K. Moon <kmoon@chromium.org>
Commit-Queue: Lei Zhang <thestig@chromium.org>
diff --git a/fpdfsdk/fpdf_edit_embeddertest.cpp b/fpdfsdk/fpdf_edit_embeddertest.cpp
index ce462d4..a55873b 100644
--- a/fpdfsdk/fpdf_edit_embeddertest.cpp
+++ b/fpdfsdk/fpdf_edit_embeddertest.cpp
@@ -928,6 +928,66 @@
   UnloadPage(page);
 }
 
+TEST_F(FPDFEditEmbedderTest,
+       RemoveTextObjectWithTwoPagesSharingContentStreamAndResources) {
+  // Load document with some text.
+  ASSERT_TRUE(OpenDocument("hello_world_2_pages.pdf"));
+  FPDF_PAGE page1 = LoadPage(0);
+  ASSERT_TRUE(page1);
+  FPDF_PAGE page2 = LoadPage(1);
+  ASSERT_TRUE(page2);
+
+  // Show what the original file looks like.
+  {
+    ScopedFPDFBitmap page1_bitmap = RenderPage(page1);
+    CompareBitmap(page1_bitmap.get(), 200, 200, HelloWorldChecksum());
+    ScopedFPDFBitmap page2_bitmap = RenderPage(page2);
+    CompareBitmap(page2_bitmap.get(), 200, 200, HelloWorldChecksum());
+  }
+
+  // Get the "Hello, world!" text object from page 1 and remove it.
+  ASSERT_EQ(2, FPDFPage_CountObjects(page1));
+  {
+    ScopedFPDFPageObject page_object(FPDFPage_GetObject(page1, 0));
+    ASSERT_TRUE(page_object);
+    ASSERT_EQ(FPDF_PAGEOBJ_TEXT, FPDFPageObj_GetType(page_object.get()));
+    EXPECT_TRUE(FPDFPage_RemoveObject(page1, page_object.get()));
+  }
+  ASSERT_EQ(1, FPDFPage_CountObjects(page1));
+
+  // Verify the "Hello, world!" text is gone from page 1.
+  {
+    ScopedFPDFBitmap page1_bitmap = RenderPage(page1);
+    CompareBitmap(page1_bitmap.get(), 200, 200, FirstRemovedChecksum());
+    ScopedFPDFBitmap page2_bitmap = RenderPage(page2);
+    CompareBitmap(page2_bitmap.get(), 200, 200, HelloWorldChecksum());
+  }
+
+  // Verify the rendering again after calling FPDFPage_GenerateContent().
+  ASSERT_TRUE(FPDFPage_GenerateContent(page1));
+  {
+    ScopedFPDFBitmap page1_bitmap = RenderPage(page1);
+    CompareBitmap(page1_bitmap.get(), 200, 200, FirstRemovedChecksum());
+    ScopedFPDFBitmap page2_bitmap = RenderPage(page2);
+    CompareBitmap(page2_bitmap.get(), 200, 200, HelloWorldChecksum());
+  }
+
+  // Save the document and verify it after reloading.
+  ASSERT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
+  ASSERT_TRUE(OpenSavedDocument());
+  FPDF_PAGE saved_page1 = LoadSavedPage(0);
+  VerifySavedRendering(saved_page1, 200, 200, FirstRemovedChecksum());
+  CloseSavedPage(saved_page1);
+  FPDF_PAGE saved_page2 = LoadSavedPage(1);
+  // TODO(crbug.com/pdfium/2012): Should be `HelloWorldChecksum()`.
+  VerifySavedRendering(saved_page2, 200, 200, FirstRemovedChecksum());
+  CloseSavedPage(saved_page2);
+  CloseSavedDocument();
+
+  UnloadPage(page1);
+  UnloadPage(page2);
+}
+
 void CheckMarkCounts(FPDF_PAGE page,
                      int start_from,
                      int expected_object_count,
diff --git a/testing/resources/hello_world_2_pages.in b/testing/resources/hello_world_2_pages.in
new file mode 100644
index 0000000..ec33354
--- /dev/null
+++ b/testing/resources/hello_world_2_pages.in
@@ -0,0 +1,67 @@
+{{header}}
+{{object 1 0}} <<
+  /Type /Catalog
+  /Pages 2 0 R
+>>
+endobj
+{{object 2 0}} <<
+  /Type /Pages
+  /Count 2
+  /Kids [3 0 R 4 0 R]
+  /MediaBox [0 0 200 200]
+>>
+endobj
+{{object 3 0}} <<
+  /Type /Page
+  /Parent 2 0 R
+  /Resources <<
+    /Font <<
+      /F1 5 0 R
+      /F2 6 0 R
+    >>
+  >>
+  /Contents 7 0 R
+>>
+endobj
+{{object 4 0}} <<
+  /Type /Page
+  /Parent 2 0 R
+  /Resources <<
+    /Font <<
+      /F1 5 0 R
+      /F2 6 0 R
+    >>
+  >>
+  /Contents 7 0 R
+>>
+endobj
+{{object 5 0}} <<
+  /Type /Font
+  /Subtype /Type1
+  /BaseFont /Times-Roman
+>>
+endobj
+{{object 6 0}} <<
+  /Type /Font
+  /Subtype /Type1
+  /BaseFont /Helvetica
+>>
+endobj
+{{object 7 0}} <<
+  {{streamlen}}
+>>
+stream
+BT
+20 50 Td
+/F1 12 Tf
+(Hello, world!) Tj
+0 50 Td
+/F2 16 Tf
+(Goodbye, world!) Tj
+ET
+endstream
+endobj
+{{xref}}
+{{trailer}}
+{{startxref}}
+%%EOF
diff --git a/testing/resources/hello_world_2_pages.pdf b/testing/resources/hello_world_2_pages.pdf
new file mode 100644
index 0000000..4942e3a
--- /dev/null
+++ b/testing/resources/hello_world_2_pages.pdf
@@ -0,0 +1,81 @@
+%PDF-1.7
+% ò¤ô
+1 0 obj <<
+  /Type /Catalog
+  /Pages 2 0 R
+>>
+endobj
+2 0 obj <<
+  /Type /Pages
+  /MediaBox [0 0 200 200]
+  /Count 2
+  /Kids [3 0 R 4 0 R]
+>>
+endobj
+3 0 obj <<
+  /Type /Page
+  /Parent 2 0 R
+  /Resources <<
+    /Font <<
+      /F1 5 0 R
+      /F2 6 0 R
+    >>
+  >>
+  /Contents 7 0 R
+>>
+endobj
+4 0 obj <<
+  /Type /Page
+  /Parent 2 0 R
+  /Resources <<
+    /Font <<
+      /F1 5 0 R
+      /F2 6 0 R
+    >>
+  >>
+  /Contents 7 0 R
+>>
+endobj
+5 0 obj <<
+  /Type /Font
+  /Subtype /Type1
+  /BaseFont /Times-Roman
+>>
+endobj
+6 0 obj <<
+  /Type /Font
+  /Subtype /Type1
+  /BaseFont /Helvetica
+>>
+endobj
+7 0 obj <<
+  /Length 83
+>>
+stream
+BT
+20 50 Td
+/F1 12 Tf
+(Hello, world!) Tj
+0 50 Td
+/F2 16 Tf
+(Goodbye, world!) Tj
+ET
+endstream
+endobj
+xref
+0 8
+0000000000 65535 f 
+0000000015 00000 n 
+0000000068 00000 n 
+0000000163 00000 n 
+0000000305 00000 n 
+0000000447 00000 n 
+0000000525 00000 n 
+0000000601 00000 n 
+trailer <<
+  /Root 1 0 R
+  /Size 8
+>>
+startxref
+735
+%%EOF