Add path objects tests for a PDF saving bug
Add FPDFEditPathEmbedderTest cases to demonstrate a PDF saving bug,
where a no-op FPDFPageObj_SetMatrix() call causes the saved PDF to have
incorrect transformation matrices. These test cases cover path objects
and path objects in forms.
Bug: pdfium:2132
Change-Id: I81f13fa6a471c4f7184e43f105ff0cc151bfccff
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/117052
Reviewed-by: Tom Sepez <tsepez@chromium.org>
Commit-Queue: Lei Zhang <thestig@chromium.org>
Reviewed-by: Thomas Sepez <tsepez@google.com>
diff --git a/fpdfsdk/fpdf_editpath_embeddertest.cpp b/fpdfsdk/fpdf_editpath_embeddertest.cpp
index 2a889d0..91103aa 100644
--- a/fpdfsdk/fpdf_editpath_embeddertest.cpp
+++ b/fpdfsdk/fpdf_editpath_embeddertest.cpp
@@ -4,10 +4,14 @@
#include "core/fxcrt/check.h"
#include "core/fxcrt/fx_system.h"
+#include "core/fxge/cfx_defaultrenderdevice.h"
#include "public/fpdf_edit.h"
#include "testing/embedder_test.h"
+#include "testing/embedder_test_constants.h"
#include "testing/gtest/include/gtest/gtest.h"
+using pdfium::RectanglesChecksum;
+
class FPDFEditPathEmbedderTest : public EmbedderTest {};
TEST_F(FPDFEditPathEmbedderTest, VerifyCorrectColoursReturned) {
@@ -62,3 +66,132 @@
CloseSavedPage(page);
CloseSavedDocument();
}
+
+TEST_F(FPDFEditPathEmbedderTest, GetAndSetMatrixForPath) {
+ constexpr int kExpectedWidth = 200;
+ constexpr int kExpectedHeight = 300;
+
+ OpenDocument("rectangles_double_flipped.pdf");
+ FPDF_PAGE page = LoadPage(0);
+ ASSERT_TRUE(page);
+
+ {
+ ScopedFPDFBitmap bitmap = RenderLoadedPage(page);
+ CompareBitmap(bitmap.get(), kExpectedWidth, kExpectedHeight,
+ RectanglesChecksum());
+ }
+
+ FPDF_PAGEOBJECT path = FPDFPage_GetObject(page, 0);
+ ASSERT_TRUE(path);
+ ASSERT_EQ(FPDF_PAGEOBJ_PATH, FPDFPageObj_GetType(path));
+
+ FS_MATRIX matrix;
+ ASSERT_TRUE(FPDFPageObj_GetMatrix(path, &matrix));
+ EXPECT_FLOAT_EQ(1.0f, matrix.a);
+ EXPECT_FLOAT_EQ(0.0f, matrix.b);
+ EXPECT_FLOAT_EQ(0.0f, matrix.c);
+ EXPECT_FLOAT_EQ(-1.0f, matrix.d);
+ EXPECT_FLOAT_EQ(0.0f, matrix.e);
+ EXPECT_FLOAT_EQ(300.0f, matrix.f);
+
+ ASSERT_TRUE(FPDFPageObj_SetMatrix(path, &matrix));
+ {
+ ScopedFPDFBitmap bitmap = RenderLoadedPage(page);
+ CompareBitmap(bitmap.get(), kExpectedWidth, kExpectedHeight,
+ RectanglesChecksum());
+ }
+
+ ASSERT_TRUE(FPDFPage_GenerateContent(page));
+ ASSERT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
+
+ {
+ ScopedFPDFBitmap bitmap = RenderLoadedPage(page);
+ CompareBitmap(bitmap.get(), kExpectedWidth, kExpectedHeight,
+ RectanglesChecksum());
+ }
+
+ UnloadPage(page);
+
+ // TODO(crbug.com/pdfium/2132): This should use RectanglesChecksum().
+ const char* const kWrongChecksum = []() {
+ if (CFX_DefaultRenderDevice::UseSkiaRenderer()) {
+ return "a8b00bc40677a73c15a08b9769d1b576";
+ }
+ return "8f3a555ef9c0d5031831ae3715273707";
+ }();
+ VerifySavedDocument(kExpectedWidth, kExpectedHeight, kWrongChecksum);
+}
+
+TEST_F(FPDFEditPathEmbedderTest, GetAndSetMatrixForFormWithPath) {
+ constexpr int kExpectedWidth = 200;
+ constexpr int kExpectedHeight = 300;
+
+ OpenDocument("form_object_with_path.pdf");
+ FPDF_PAGE page = LoadPage(0);
+ ASSERT_TRUE(page);
+
+ {
+ ScopedFPDFBitmap bitmap = RenderLoadedPage(page);
+ CompareBitmap(bitmap.get(), kExpectedWidth, kExpectedHeight,
+ RectanglesChecksum());
+ }
+
+ FPDF_PAGEOBJECT form = FPDFPage_GetObject(page, 0);
+ ASSERT_TRUE(form);
+ ASSERT_EQ(FPDF_PAGEOBJ_FORM, FPDFPageObj_GetType(form));
+
+ FS_MATRIX matrix;
+ ASSERT_TRUE(FPDFPageObj_GetMatrix(form, &matrix));
+ EXPECT_FLOAT_EQ(2.0f, matrix.a);
+ EXPECT_FLOAT_EQ(0.0f, matrix.b);
+ EXPECT_FLOAT_EQ(0.0f, matrix.c);
+ EXPECT_FLOAT_EQ(-1.0f, matrix.d);
+ EXPECT_FLOAT_EQ(0.0f, matrix.e);
+ EXPECT_FLOAT_EQ(300.0f, matrix.f);
+
+ ASSERT_TRUE(FPDFPageObj_SetMatrix(form, &matrix));
+ {
+ ScopedFPDFBitmap bitmap = RenderLoadedPage(page);
+ CompareBitmap(bitmap.get(), kExpectedWidth, kExpectedHeight,
+ RectanglesChecksum());
+ }
+
+ FPDF_PAGEOBJECT path = FPDFFormObj_GetObject(form, 0);
+ ASSERT_TRUE(path);
+ ASSERT_EQ(FPDF_PAGEOBJ_PATH, FPDFPageObj_GetType(path));
+
+ ASSERT_TRUE(FPDFPageObj_GetMatrix(path, &matrix));
+ EXPECT_FLOAT_EQ(0.5f, matrix.a);
+ EXPECT_FLOAT_EQ(0.0f, matrix.b);
+ EXPECT_FLOAT_EQ(0.0f, matrix.c);
+ EXPECT_FLOAT_EQ(-1.0f, matrix.d);
+ EXPECT_FLOAT_EQ(0.0f, matrix.e);
+ EXPECT_FLOAT_EQ(300.0f, matrix.f);
+
+ ASSERT_TRUE(FPDFPageObj_SetMatrix(path, &matrix));
+ {
+ ScopedFPDFBitmap bitmap = RenderLoadedPage(page);
+ CompareBitmap(bitmap.get(), kExpectedWidth, kExpectedHeight,
+ RectanglesChecksum());
+ }
+
+ ASSERT_TRUE(FPDFPage_GenerateContent(page));
+ ASSERT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
+
+ {
+ ScopedFPDFBitmap bitmap = RenderLoadedPage(page);
+ CompareBitmap(bitmap.get(), kExpectedWidth, kExpectedHeight,
+ RectanglesChecksum());
+ }
+
+ UnloadPage(page);
+
+ // TODO(crbug.com/pdfium/2132): This should use RectanglesChecksum().
+ const char* const kWrongChecksum = []() {
+ if (CFX_DefaultRenderDevice::UseSkiaRenderer()) {
+ return "f7c69f8d0bb92541d48dbbbba003396d";
+ }
+ return "37a215071985bd88079fedb56b001685";
+ }();
+ VerifySavedDocument(kExpectedWidth, kExpectedHeight, kWrongChecksum);
+}
diff --git a/testing/resources/form_object_with_path.in b/testing/resources/form_object_with_path.in
new file mode 100644
index 0000000..aeb1dac
--- /dev/null
+++ b/testing/resources/form_object_with_path.in
@@ -0,0 +1,63 @@
+{{header}}
+{{object 1 0}} <<
+ /Type /Catalog
+ /Pages 2 0 R
+>>
+endobj
+{{object 2 0}} <<
+ /Type /Pages
+ /MediaBox [0 0 200 300]
+ /Count 1
+ /Kids [3 0 R]
+>>
+endobj
+{{object 3 0}} <<
+ /Type /Page
+ /Parent 2 0 R
+ /Contents 4 0 R
+ /Resources <<
+ /XObject <<
+ /F1 5 0 R
+ >>
+ >>
+>>
+endobj
+{{object 4 0}} <<
+ {{streamlen}}
+>>
+stream
+2 0 0 -1 0 300 cm
+q
+/F1 Do
+Q
+endstream
+endobj
+{{object 5 0}} <<
+ /Type /XObject
+ /Subtype /Form
+ /BBox [0 0 200 300]
+>>
+stream
+q
+0.5 0 0 -1 0 300 cm
+q
+0 0 0 rg
+0 290 10 10 re B*
+10 150 50 30 re B*
+0 0 1 rg
+190 290 10 10 re B*
+70 232 50 30 re B*
+0 1 0 rg
+190 0 10 10 re B*
+130 150 50 30 re B*
+1 0 0 rg
+0 0 10 10 re B*
+70 67 50 30 re B*
+Q
+Q
+endstream
+endobj
+{{xref}}
+{{trailer}}
+{{startxref}}
+%%EOF
diff --git a/testing/resources/form_object_with_path.pdf b/testing/resources/form_object_with_path.pdf
new file mode 100644
index 0000000..a49dd0c
--- /dev/null
+++ b/testing/resources/form_object_with_path.pdf
@@ -0,0 +1,75 @@
+%PDF-1.7
+% ò¤ô
+1 0 obj <<
+ /Type /Catalog
+ /Pages 2 0 R
+>>
+endobj
+2 0 obj <<
+ /Type /Pages
+ /MediaBox [0 0 200 300]
+ /Count 1
+ /Kids [3 0 R]
+>>
+endobj
+3 0 obj <<
+ /Type /Page
+ /Parent 2 0 R
+ /Contents 4 0 R
+ /Resources <<
+ /XObject <<
+ /F1 5 0 R
+ >>
+ >>
+>>
+endobj
+4 0 obj <<
+ /Length 29
+>>
+stream
+2 0 0 -1 0 300 cm
+q
+/F1 Do
+Q
+endstream
+endobj
+5 0 obj <<
+ /Type /XObject
+ /Subtype /Form
+ /BBox [0 0 200 300]
+>>
+stream
+q
+0.5 0 0 -1 0 300 cm
+q
+0 0 0 rg
+0 290 10 10 re B*
+10 150 50 30 re B*
+0 0 1 rg
+190 290 10 10 re B*
+70 232 50 30 re B*
+0 1 0 rg
+190 0 10 10 re B*
+130 150 50 30 re B*
+1 0 0 rg
+0 0 10 10 re B*
+70 67 50 30 re B*
+Q
+Q
+endstream
+endobj
+xref
+0 6
+0000000000 65535 f
+0000000015 00000 n
+0000000068 00000 n
+0000000157 00000 n
+0000000286 00000 n
+0000000366 00000 n
+trailer <<
+ /Root 1 0 R
+ /Size 6
+>>
+startxref
+672
+%%EOF
diff --git a/testing/resources/rectangles_double_flipped.in b/testing/resources/rectangles_double_flipped.in
new file mode 100644
index 0000000..e2f8a95
--- /dev/null
+++ b/testing/resources/rectangles_double_flipped.in
@@ -0,0 +1,44 @@
+{{header}}
+{{object 1 0}} <<
+ /Type /Catalog
+ /Pages 2 0 R
+>>
+endobj
+{{object 2 0}} <<
+ /Type /Pages
+ /MediaBox [0 0 200 300]
+ /Count 1
+ /Kids [3 0 R]
+>>
+endobj
+{{object 3 0}} <<
+ /Type /Page
+ /Parent 2 0 R
+ /Contents 4 0 R
+>>
+endobj
+{{object 4 0}} <<
+ {{streamlen}}
+>>
+stream
+1 0 0 -1 0 300 cm
+q
+0 0 0 rg
+0 10 10 -10 re B*
+10 150 50 -30 re B*
+0 0 1 rg
+190 10 10 -10 re B*
+70 68 50 -30 re B*
+0 1 0 rg
+190 300 10 -10 re B*
+130 150 50 -30 re B*
+1 0 0 rg
+0 300 10 -10 re B*
+70 233 50 -30 re B*
+Q
+endstream
+endobj
+{{xref}}
+{{trailer}}
+{{startxref}}
+%%EOF
diff --git a/testing/resources/rectangles_double_flipped.pdf b/testing/resources/rectangles_double_flipped.pdf
new file mode 100644
index 0000000..1180401
--- /dev/null
+++ b/testing/resources/rectangles_double_flipped.pdf
@@ -0,0 +1,55 @@
+%PDF-1.7
+% ò¤ô
+1 0 obj <<
+ /Type /Catalog
+ /Pages 2 0 R
+>>
+endobj
+2 0 obj <<
+ /Type /Pages
+ /MediaBox [0 0 200 300]
+ /Count 1
+ /Kids [3 0 R]
+>>
+endobj
+3 0 obj <<
+ /Type /Page
+ /Parent 2 0 R
+ /Contents 4 0 R
+>>
+endobj
+4 0 obj <<
+ /Length 216
+>>
+stream
+1 0 0 -1 0 300 cm
+q
+0 0 0 rg
+0 10 10 -10 re B*
+10 150 50 -30 re B*
+0 0 1 rg
+190 10 10 -10 re B*
+70 68 50 -30 re B*
+0 1 0 rg
+190 300 10 -10 re B*
+130 150 50 -30 re B*
+1 0 0 rg
+0 300 10 -10 re B*
+70 233 50 -30 re B*
+Q
+endstream
+endobj
+xref
+0 5
+0000000000 65535 f
+0000000015 00000 n
+0000000068 00000 n
+0000000157 00000 n
+0000000226 00000 n
+trailer <<
+ /Root 1 0 R
+ /Size 5
+>>
+startxref
+494
+%%EOF