Add embedder tests for page box mutators and clip path transform

Exercise FPDFPage_SetBleedBox, FPDFPage_SetTrimBox, and
FPDFPage_SetArtBox in FPDFTransformEmbedderTest, verifying that the
bounding box values update on the live page and persist across saving
and reloading.

Also exercise FPDFPageObj_TransformClipPath in FPDFEditEmbedderTest,
verifying that matrix scaling and translation correctly transform the
path segments of a page object's clip path.

Bug: 42270238
Change-Id: I01c25cdb08fd8f2f04d594d09cac9f5a827c9ad3
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/163650
Commit-Queue: Tom Sepez <tsepez@chromium.org>
Reviewed-by: Lei Zhang <thestig@chromium.org>
diff --git a/fpdfsdk/fpdf_edit_embeddertest.cpp b/fpdfsdk/fpdf_edit_embeddertest.cpp
index bea12c8..6c0fe50 100644
--- a/fpdfsdk/fpdf_edit_embeddertest.cpp
+++ b/fpdfsdk/fpdf_edit_embeddertest.cpp
@@ -37,6 +37,7 @@
 #include "public/fpdf_annot.h"
 #include "public/fpdf_doc.h"
 #include "public/fpdf_edit.h"
+#include "public/fpdf_transformpage.h"
 #include "public/fpdfview.h"
 #include "testing/embedder_test.h"
 #include "testing/embedder_test_constants.h"
@@ -689,6 +690,36 @@
   EXPECT_EQ(35, y);
   EXPECT_EQ(FPDF_SEGMENT_LINETO, FPDFPathSegment_GetType(segment));
   EXPECT_FALSE(FPDFPathSegment_GetClose(segment));
+
+  // Null object does not crash.
+  FPDFPageObj_TransformClipPath(nullptr, 2.0, 0.0, 0.0, 3.0, 100.0, 200.0);
+
+  // Transform clip path: scale X by 2, scale Y by 3, translate (100, 200).
+  FPDFPageObj_TransformClipPath(triangle, 2.0, 0.0, 0.0, 3.0, 100.0, 200.0);
+
+  segment = FPDFClipPath_GetPathSegment(clip_path, 0, 0);
+  ASSERT_TRUE(segment);
+  EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
+  EXPECT_FLOAT_EQ(120.0f, x);
+  EXPECT_FLOAT_EQ(245.0f, y);
+
+  segment = FPDFClipPath_GetPathSegment(clip_path, 0, 1);
+  ASSERT_TRUE(segment);
+  EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
+  EXPECT_FLOAT_EQ(180.0f, x);
+  EXPECT_FLOAT_EQ(245.0f, y);
+
+  segment = FPDFClipPath_GetPathSegment(clip_path, 0, 2);
+  ASSERT_TRUE(segment);
+  EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
+  EXPECT_FLOAT_EQ(180.0f, x);
+  EXPECT_FLOAT_EQ(305.0f, y);
+
+  segment = FPDFClipPath_GetPathSegment(clip_path, 0, 3);
+  ASSERT_TRUE(segment);
+  EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
+  EXPECT_FLOAT_EQ(120.0f, x);
+  EXPECT_FLOAT_EQ(305.0f, y);
 }
 
 TEST_F(FPDFEditEmbedderTest, Bug1399) {
diff --git a/fpdfsdk/fpdf_transformpage_embeddertest.cpp b/fpdfsdk/fpdf_transformpage_embeddertest.cpp
index 2be3ea0..2d50aa4 100644
--- a/fpdfsdk/fpdf_transformpage_embeddertest.cpp
+++ b/fpdfsdk/fpdf_transformpage_embeddertest.cpp
@@ -331,6 +331,127 @@
   }
 }
 
+TEST_F(FPDFTransformEmbedderTest, SetBleedBox) {
+  {
+    ASSERT_TRUE(OpenDocument("rectangles.pdf"));
+    ScopedPage page = LoadScopedPage(0);
+    ASSERT_TRUE(page);
+
+    FS_RECTF bleedbox;
+    EXPECT_FALSE(FPDFPage_GetBleedBox(page.get(), &bleedbox.left,
+                                      &bleedbox.bottom, &bleedbox.right,
+                                      &bleedbox.top));
+
+    // Null page does not crash.
+    FPDFPage_SetBleedBox(nullptr, 15, 25, 120, 180);
+
+    FPDFPage_SetBleedBox(page.get(), 15, 25, 120, 180);
+    EXPECT_TRUE(FPDFPage_GetBleedBox(page.get(), &bleedbox.left,
+                                     &bleedbox.bottom, &bleedbox.right,
+                                     &bleedbox.top));
+    EXPECT_EQ(15, bleedbox.left);
+    EXPECT_EQ(25, bleedbox.bottom);
+    EXPECT_EQ(120, bleedbox.right);
+    EXPECT_EQ(180, bleedbox.top);
+  }
+
+  {
+    EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
+    ScopedSavedDoc saved_document = OpenScopedSavedDocument();
+    ASSERT_TRUE(saved_document);
+    ScopedSavedPage saved_page = LoadScopedSavedPage(0);
+    ASSERT_TRUE(saved_page);
+
+    FS_RECTF bleedbox;
+    EXPECT_TRUE(FPDFPage_GetBleedBox(saved_page.get(), &bleedbox.left,
+                                     &bleedbox.bottom, &bleedbox.right,
+                                     &bleedbox.top));
+    EXPECT_EQ(15, bleedbox.left);
+    EXPECT_EQ(25, bleedbox.bottom);
+    EXPECT_EQ(120, bleedbox.right);
+    EXPECT_EQ(180, bleedbox.top);
+  }
+}
+
+TEST_F(FPDFTransformEmbedderTest, SetTrimBox) {
+  {
+    ASSERT_TRUE(OpenDocument("rectangles.pdf"));
+    ScopedPage page = LoadScopedPage(0);
+    ASSERT_TRUE(page);
+
+    FS_RECTF trimbox;
+    EXPECT_FALSE(FPDFPage_GetTrimBox(page.get(), &trimbox.left, &trimbox.bottom,
+                                     &trimbox.right, &trimbox.top));
+
+    // Null page does not crash.
+    FPDFPage_SetTrimBox(nullptr, 20, 30, 110, 170);
+
+    FPDFPage_SetTrimBox(page.get(), 20, 30, 110, 170);
+    EXPECT_TRUE(FPDFPage_GetTrimBox(page.get(), &trimbox.left, &trimbox.bottom,
+                                    &trimbox.right, &trimbox.top));
+    EXPECT_EQ(20, trimbox.left);
+    EXPECT_EQ(30, trimbox.bottom);
+    EXPECT_EQ(110, trimbox.right);
+    EXPECT_EQ(170, trimbox.top);
+  }
+
+  {
+    EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
+    ScopedSavedDoc saved_document = OpenScopedSavedDocument();
+    ASSERT_TRUE(saved_document);
+    ScopedSavedPage saved_page = LoadScopedSavedPage(0);
+    ASSERT_TRUE(saved_page);
+
+    FS_RECTF trimbox;
+    EXPECT_TRUE(FPDFPage_GetTrimBox(saved_page.get(), &trimbox.left,
+                                    &trimbox.bottom, &trimbox.right,
+                                    &trimbox.top));
+    EXPECT_EQ(20, trimbox.left);
+    EXPECT_EQ(30, trimbox.bottom);
+    EXPECT_EQ(110, trimbox.right);
+    EXPECT_EQ(170, trimbox.top);
+  }
+}
+
+TEST_F(FPDFTransformEmbedderTest, SetArtBox) {
+  {
+    ASSERT_TRUE(OpenDocument("rectangles.pdf"));
+    ScopedPage page = LoadScopedPage(0);
+    ASSERT_TRUE(page);
+
+    FS_RECTF artbox;
+    EXPECT_FALSE(FPDFPage_GetArtBox(page.get(), &artbox.left, &artbox.bottom,
+                                    &artbox.right, &artbox.top));
+
+    // Null page does not crash.
+    FPDFPage_SetArtBox(nullptr, 25, 35, 100, 160);
+
+    FPDFPage_SetArtBox(page.get(), 25, 35, 100, 160);
+    EXPECT_TRUE(FPDFPage_GetArtBox(page.get(), &artbox.left, &artbox.bottom,
+                                   &artbox.right, &artbox.top));
+    EXPECT_EQ(25, artbox.left);
+    EXPECT_EQ(35, artbox.bottom);
+    EXPECT_EQ(100, artbox.right);
+    EXPECT_EQ(160, artbox.top);
+  }
+
+  {
+    EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
+    ScopedSavedDoc saved_document = OpenScopedSavedDocument();
+    ASSERT_TRUE(saved_document);
+    ScopedSavedPage saved_page = LoadScopedSavedPage(0);
+    ASSERT_TRUE(saved_page);
+
+    FS_RECTF artbox;
+    EXPECT_TRUE(FPDFPage_GetArtBox(saved_page.get(), &artbox.left,
+                                   &artbox.bottom, &artbox.right, &artbox.top));
+    EXPECT_EQ(25, artbox.left);
+    EXPECT_EQ(35, artbox.bottom);
+    EXPECT_EQ(100, artbox.right);
+    EXPECT_EQ(160, artbox.top);
+  }
+}
+
 TEST_F(FPDFTransformEmbedderTest, ClipPath) {
   ASSERT_TRUE(OpenDocument("hello_world.pdf"));