Add an embedder test for crbug.com/pdfium/1893

Adds an embedder test to prove that removing an object sometimes
affects the content stream matrix unexpectedly.

Bug: pdfium:1893
Change-Id: I997c3c094078b768f0ffffc2a5a04084ba05a1e2
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/111870
Reviewed-by: Lei Zhang <thestig@chromium.org>
Commit-Queue: Nigi <nigi@chromium.org>
diff --git a/fpdfsdk/fpdf_edit_embeddertest.cpp b/fpdfsdk/fpdf_edit_embeddertest.cpp
index f22aa86..02edaf0 100644
--- a/fpdfsdk/fpdf_edit_embeddertest.cpp
+++ b/fpdfsdk/fpdf_edit_embeddertest.cpp
@@ -922,6 +922,76 @@
   CloseSavedDocument();
 }
 
+TEST_F(FPDFEditEmbedderTest, BUG_1893) {
+  ASSERT_TRUE(OpenDocument("bug_1893.pdf"));
+  FPDF_PAGE page = LoadPage(0);
+  {
+    const char* original_checksum = []() {
+      if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer()) {
+        return "d8be4379e729242785945458924318a3";
+      }
+#if BUILDFLAG(IS_APPLE)
+      return "0964322399241618539b474dbf9d40c6";
+#else
+      return "c3672f206e47d98677401f1617ad56eb";
+#endif
+    }();
+
+    ScopedFPDFBitmap bitmap = RenderLoadedPage(page);
+    CompareBitmap(bitmap.get(), 200, 300, original_checksum);
+  }
+
+  EXPECT_EQ(3, FPDFPage_CountObjects(page));
+
+  const char* removed_checksum = []() {
+    if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer()) {
+      return "4a02191e033dddeb2110d55af3f14544";
+    }
+#if BUILDFLAG(IS_APPLE)
+    return "d0837f2b8809a5902d3c4219441fbafe";
+#else
+    return "e9c0cbd6adcb2151b4e36a61ab26a20a";
+#endif
+  }();
+
+  // Remove the underline and regenerate the page content.
+  {
+    ScopedFPDFPageObject object(FPDFPage_GetObject(page, 0));
+    ASSERT_TRUE(FPDFPage_RemoveObject(page, object.get()));
+    ASSERT_TRUE(FPDFPage_GenerateContent(page));
+
+    ScopedFPDFBitmap bitmap = RenderLoadedPage(page);
+    CompareBitmap(bitmap.get(), 200, 300, removed_checksum);
+  }
+
+  ASSERT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
+  UnloadPage(page);
+
+  {
+    // TODO(crbug.com/pdfium/1893): The saved result should match
+    // `removed_checksum`. But in the actual saved result, the remaining text
+    // objects were upside down. Remove `wrong_checksum` after fixing this
+    // issue.
+    const char* wrong_checksum = []() {
+      if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer()) {
+        return "57da26dcb24503403cadb27ed8bb46c6";
+      }
+#if BUILDFLAG(IS_APPLE)
+      return "c3b6a8ecd863914044f5f79137c606b5";
+#else
+      return "cb19480a846e4efd36418cbd7412118e";
+#endif
+    }();
+
+    ASSERT_TRUE(OpenSavedDocument());
+    FPDF_PAGE saved_page = LoadSavedPage(0);
+    ScopedFPDFBitmap bitmap = RenderSavedPageWithFlags(saved_page, FPDF_ANNOT);
+    CompareBitmap(bitmap.get(), 200, 300, wrong_checksum);
+    CloseSavedPage(saved_page);
+    CloseSavedDocument();
+  }
+}
+
 TEST_F(FPDFEditEmbedderTest, RemoveTextObject) {
   // Load document with some text.
   ASSERT_TRUE(OpenDocument("hello_world.pdf"));
diff --git a/testing/resources/bug_1893.in b/testing/resources/bug_1893.in
new file mode 100644
index 0000000..009f503
--- /dev/null
+++ b/testing/resources/bug_1893.in
@@ -0,0 +1,59 @@
+{{header}}
+{{object 1 0}} <<
+  /Type /Catalog
+  /Pages 2 0 R
+>>
+endobj
+{{object 2 0}} <<
+  /Type /Pages
+  /Count 1
+  /Kids [3 0 R]
+>>
+endobj
+{{object 3 0}} <<
+  /Type /Page
+  /Parent 2 0 R
+  /Contents 4 0 R
+  /MediaBox [0 0 200 300]
+  /Resources <<
+    /Font <<
+      /F0 5 0 R
+    >>
+  >>
+>>
+endobj
+{{object 4 0}} <<
+  {{streamlen}}
+>>
+stream
+1 0 0 -1 0 300 cm
+q
+0 0 0 rg
+40 100 140 1 re f
+Q
+q
+0 0 0 rg
+BT
+12 0 0 -12 150 100 Tm
+/F0 1 Tf
+(Hello) Tj
+ET
+q
+BT
+12 0 0 -12 100 200 Tm
+/F0 1 Tf
+(world!) Tj
+ET
+Q
+Q
+endstream
+endobj
+{{object 5 0}} <<
+  /Type /Font
+  /Subtype /Type1
+  /BaseFont /Times-Roman
+endobj
+{{xref}}
+{{trailer}}
+{{startxref}}
+%%EOF
diff --git a/testing/resources/bug_1893.pdf b/testing/resources/bug_1893.pdf
new file mode 100644
index 0000000..448f994
--- /dev/null
+++ b/testing/resources/bug_1893.pdf
@@ -0,0 +1,71 @@
+%PDF-1.7
+% ò¤ô
+1 0 obj <<
+  /Type /Catalog
+  /Pages 2 0 R
+>>
+endobj
+2 0 obj <<
+  /Type /Pages
+  /Count 1
+  /Kids [3 0 R]
+>>
+endobj
+3 0 obj <<
+  /Type /Page
+  /Parent 2 0 R
+  /Contents 4 0 R
+  /MediaBox [0 0 200 300]
+  /Resources <<
+    /Font <<
+      /F0 5 0 R
+    >>
+  >>
+>>
+endobj
+4 0 obj <<
+  /Length 163
+>>
+stream
+1 0 0 -1 0 300 cm
+q
+0 0 0 rg
+40 100 140 1 re f
+Q
+q
+0 0 0 rg
+BT
+12 0 0 -12 150 100 Tm
+/F0 1 Tf
+(Hello) Tj
+ET
+q
+BT
+12 0 0 -12 100 200 Tm
+/F0 1 Tf
+(world!) Tj
+ET
+Q
+Q
+endstream
+endobj
+5 0 obj <<
+  /Type /Font
+  /Subtype /Type1
+  /BaseFont /Times-Roman
+endobj
+xref
+0 6
+0000000000 65535 f 
+0000000015 00000 n 
+0000000068 00000 n 
+0000000131 00000 n 
+0000000283 00000 n 
+0000000498 00000 n 
+trailer <<
+  /Root 1 0 R
+  /Size 6
+>>
+startxref
+573
+%%EOF