Add tests for device to page and page to device coordinate conversions

Tests for FPDF_DeviceToPage()
Normal case: device coordinate (10, 10) is passed and output value is
compared against expected value. Test includes variations for rotation.
Negative cases: invalid parameters

Tests for FPDF_PageToDevice()
Normal case: page coordinate (9, 775) is passed and output is compared
against expected value. Test includes variations for rotation.
Negative cases: invalid parameters

R=thestig@chromium.org

Bug: pdfium:1239
Change-Id: I90cf4b12e24ac565af313b02166368b2bcbac7ea
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/51090
Reviewed-by: Lei Zhang <thestig@chromium.org>
Commit-Queue: Lei Zhang <thestig@chromium.org>
diff --git a/fpdfsdk/fpdf_view_embeddertest.cpp b/fpdfsdk/fpdf_view_embeddertest.cpp
index ff03a32..cade1ca 100644
--- a/fpdfsdk/fpdf_view_embeddertest.cpp
+++ b/fpdfsdk/fpdf_view_embeddertest.cpp
@@ -48,6 +48,170 @@
                                       const char* expected_md5);
 };
 
+// Test for conversion of a point in device coordinates to page coordinates
+TEST_F(FPDFViewEmbedderTest, DeviceCoordinatesToPageCoordinates) {
+  EXPECT_TRUE(OpenDocument("about_blank.pdf"));
+  FPDF_PAGE page = LoadPage(0);
+  EXPECT_NE(nullptr, page);
+
+  // Error tolerance for floating point comparison
+  const double kTolerance = 0.0001;
+
+  // Display bounds in device coordinates
+  int start_x = 0;
+  int start_y = 0;
+  int size_x = 640;
+  int size_y = 480;
+
+  // Page Orientation normal
+  int rotate = 0;
+
+  // Device coordinate to be converted
+  int device_x = 10;
+  int device_y = 10;
+
+  double page_x = 0.0;
+  double page_y = 0.0;
+  EXPECT_TRUE(FPDF_DeviceToPage(page, start_x, start_y, size_x, size_y, rotate,
+                                device_x, device_y, &page_x, &page_y));
+  EXPECT_NEAR(9.5625, page_x, kTolerance);
+  EXPECT_NEAR(775.5, page_y, kTolerance);
+
+  // Rotate 90 degrees clockwise
+  rotate = 1;
+  EXPECT_TRUE(FPDF_DeviceToPage(page, start_x, start_y, size_x, size_y, rotate,
+                                device_x, device_y, &page_x, &page_y));
+  EXPECT_NEAR(12.75, page_x, kTolerance);
+  EXPECT_NEAR(12.375, page_y, kTolerance);
+
+  // Rotate 180 degrees
+  rotate = 2;
+  EXPECT_TRUE(FPDF_DeviceToPage(page, start_x, start_y, size_x, size_y, rotate,
+                                device_x, device_y, &page_x, &page_y));
+  EXPECT_NEAR(602.4374, page_x, kTolerance);
+  EXPECT_NEAR(16.5, page_y, kTolerance);
+
+  // Rotate 90 degrees counter-clockwise
+  rotate = 3;
+  EXPECT_TRUE(FPDF_DeviceToPage(page, start_x, start_y, size_x, size_y, rotate,
+                                device_x, device_y, &page_x, &page_y));
+  EXPECT_NEAR(599.25, page_x, kTolerance);
+  EXPECT_NEAR(779.625, page_y, kTolerance);
+
+  // FPDF_DeviceToPage() converts |rotate| into legal rotation by taking
+  // modulo by 4. A value of 4 is expected to be converted into 0 (normal
+  // rotation)
+  rotate = 4;
+  EXPECT_TRUE(FPDF_DeviceToPage(page, start_x, start_y, size_x, size_y, rotate,
+                                device_x, device_y, &page_x, &page_y));
+  EXPECT_NEAR(9.5625, page_x, kTolerance);
+  EXPECT_NEAR(775.5, page_y, kTolerance);
+
+  // FPDF_DeviceToPage returns untransformed coordinates if |rotate| % 4 is
+  // negative.
+  rotate = -1;
+  EXPECT_TRUE(FPDF_DeviceToPage(page, start_x, start_y, size_x, size_y, rotate,
+                                device_x, device_y, &page_x, &page_y));
+  EXPECT_NEAR(device_x, page_x, kTolerance);
+  EXPECT_NEAR(device_y, page_y, kTolerance);
+
+  // Negative case - invalid page
+  page_x = 1234.0;
+  page_y = 5678.0;
+  EXPECT_FALSE(FPDF_DeviceToPage(nullptr, start_x, start_y, size_x, size_y,
+                                 rotate, device_x, device_y, &page_x, &page_y));
+  // Out parameters are expected to remain unchanged
+  EXPECT_NEAR(1234.0, page_x, kTolerance);
+  EXPECT_NEAR(5678.0, page_y, kTolerance);
+
+  // Negative case - invalid output parameters
+  EXPECT_FALSE(FPDF_DeviceToPage(page, start_x, start_y, size_x, size_y, rotate,
+                                 device_x, device_y, nullptr, nullptr));
+
+  UnloadPage(page);
+}
+
+// Test for conversion of a point in page coordinates to device coordinates.
+TEST_F(FPDFViewEmbedderTest, PageCoordinatesToDeviceCoordinates) {
+  EXPECT_TRUE(OpenDocument("about_blank.pdf"));
+  FPDF_PAGE page = LoadPage(0);
+  EXPECT_NE(nullptr, page);
+
+  // Display bounds in device coordinates
+  int start_x = 0;
+  int start_y = 0;
+  int size_x = 640;
+  int size_y = 480;
+
+  // Page Orientation normal
+  int rotate = 0;
+
+  // Page coordinate to be converted
+  double page_x = 9.0;
+  double page_y = 775.0;
+
+  int device_x = 0;
+  int device_y = 0;
+  EXPECT_TRUE(FPDF_PageToDevice(page, start_x, start_y, size_x, size_y, rotate,
+                                page_x, page_y, &device_x, &device_y));
+
+  EXPECT_EQ(9, device_x);
+  EXPECT_EQ(10, device_y);
+
+  // Rotate 90 degrees clockwise
+  rotate = 1;
+  EXPECT_TRUE(FPDF_PageToDevice(page, start_x, start_y, size_x, size_y, rotate,
+                                page_x, page_y, &device_x, &device_y));
+  EXPECT_EQ(626, device_x);
+  EXPECT_EQ(7, device_y);
+
+  // Rotate 180 degrees
+  rotate = 2;
+  EXPECT_TRUE(FPDF_PageToDevice(page, start_x, start_y, size_x, size_y, rotate,
+                                page_x, page_y, &device_x, &device_y));
+  EXPECT_EQ(631, device_x);
+  EXPECT_EQ(470, device_y);
+
+  // Rotate 90 degrees counter-clockwise
+  rotate = 3;
+  EXPECT_TRUE(FPDF_PageToDevice(page, start_x, start_y, size_x, size_y, rotate,
+                                page_x, page_y, &device_x, &device_y));
+  EXPECT_EQ(14, device_x);
+  EXPECT_EQ(473, device_y);
+
+  // FPDF_PageToDevice() converts |rotate| into legal rotation by taking
+  // modulo by 4. A value of 4 is expected to be converted into 0 (normal
+  // rotation)
+  rotate = 4;
+  EXPECT_TRUE(FPDF_PageToDevice(page, start_x, start_y, size_x, size_y, rotate,
+                                page_x, page_y, &device_x, &device_y));
+  EXPECT_EQ(9, device_x);
+  EXPECT_EQ(10, device_y);
+
+  // FPDF_PageToDevice() returns untransformed coordinates if |rotate| % 4 is
+  // negative.
+  rotate = -1;
+  EXPECT_TRUE(FPDF_PageToDevice(page, start_x, start_y, size_x, size_y, rotate,
+                                page_x, page_y, &device_x, &device_y));
+  EXPECT_EQ(start_x, device_x);
+  EXPECT_EQ(start_y, device_y);
+
+  // Negative case - invalid page
+  device_x = 1234;
+  device_y = 5678;
+  EXPECT_FALSE(FPDF_PageToDevice(nullptr, start_x, start_y, size_x, size_y,
+                                 rotate, page_x, page_y, &device_x, &device_y));
+  // Out parameters are expected to remain unchanged
+  EXPECT_EQ(1234, device_x);
+  EXPECT_EQ(5678, device_y);
+
+  // Negative case - invalid output parameters
+  EXPECT_FALSE(FPDF_PageToDevice(page, start_x, start_y, size_x, size_y, rotate,
+                                 page_x, page_y, nullptr, nullptr));
+
+  UnloadPage(page);
+}
+
 TEST_F(FPDFViewEmbedderTest, Document) {
   EXPECT_TRUE(OpenDocument("about_blank.pdf"));
   EXPECT_EQ(1, GetPageCount());