Add some experimental float API variants in public/fpdfview.h.

These new API variants listed below use floats instead of doubles. They
are better because they work more seamlessly with the underlying
implementation, which uses floats. The original non-F variants have
notes that the they will be deprecated soon.

The new APIs in this CL are:
- FPDF_GetPageHeightF()
- FPDF_GetPageSizeByIndexF()
- FPDF_GetPageWidthF()

This CL also introduces a size struct, FS_SIZEF, so APIs like
FPDF_GetPageSizeByIndexF() can take a single size out parameter instead
of two.

Some callers have been switched to them to show they work.

Bug: pdfium:996
Change-Id: Id9b4edbcdb2b429d8ea7e49bd2faf1e0bfc9e7e4
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/61872
Commit-Queue: Lei Zhang <thestig@chromium.org>
Reviewed-by: Tom Sepez <tsepez@chromium.org>
diff --git a/fpdfsdk/fpdf_view.cpp b/fpdfsdk/fpdf_view.cpp
index e897274..40e13b8 100644
--- a/fpdfsdk/fpdf_view.cpp
+++ b/fpdfsdk/fpdf_view.cpp
@@ -355,14 +355,22 @@
   return FPDFPageFromIPDFPage(pPage.Leak());
 }
 
-FPDF_EXPORT double FPDF_CALLCONV FPDF_GetPageWidth(FPDF_PAGE page) {
+FPDF_EXPORT float FPDF_CALLCONV FPDF_GetPageWidthF(FPDF_PAGE page) {
   IPDF_Page* pPage = IPDFPageFromFPDFPage(page);
-  return pPage ? pPage->GetPageWidth() : 0.0;
+  return pPage ? pPage->GetPageWidth() : 0.0f;
+}
+
+FPDF_EXPORT double FPDF_CALLCONV FPDF_GetPageWidth(FPDF_PAGE page) {
+  return FPDF_GetPageWidthF(page);
+}
+
+FPDF_EXPORT float FPDF_CALLCONV FPDF_GetPageHeightF(FPDF_PAGE page) {
+  IPDF_Page* pPage = IPDFPageFromFPDFPage(page);
+  return pPage ? pPage->GetPageHeight() : 0.0f;
 }
 
 FPDF_EXPORT double FPDF_CALLCONV FPDF_GetPageHeight(FPDF_PAGE page) {
-  IPDF_Page* pPage = IPDFPageFromFPDFPage(page);
-  return pPage ? pPage->GetPageHeight() : 0.0;
+  return FPDF_GetPageHeightF(page);
 }
 
 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_GetPageBoundingBox(FPDF_PAGE page,
@@ -914,11 +922,11 @@
                  flags, bNeedToRestore, pause);
 }
 
-FPDF_EXPORT int FPDF_CALLCONV FPDF_GetPageSizeByIndex(FPDF_DOCUMENT document,
-                                                      int page_index,
-                                                      double* width,
-                                                      double* height) {
-  if (!width || !height)
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
+FPDF_GetPageSizeByIndexF(FPDF_DOCUMENT document,
+                         int page_index,
+                         FS_SIZEF* size) {
+  if (!size)
     return false;
 
   auto* pDoc = CPDFDocumentFromFPDFDocument(document);
@@ -935,8 +943,8 @@
     if (!pPage)
       return false;
 
-    *width = pPage->GetPageWidth();
-    *height = pPage->GetPageHeight();
+    size->width = pPage->GetPageWidth();
+    size->height = pPage->GetPageHeight();
     return true;
   }
 #endif  // PDF_ENABLE_XFA
@@ -947,8 +955,24 @@
 
   auto page = pdfium::MakeRetain<CPDF_Page>(pDoc, pDict);
   page->SetRenderCache(pdfium::MakeUnique<CPDF_PageRenderCache>(page.Get()));
-  *width = page->GetPageWidth();
-  *height = page->GetPageHeight();
+  size->width = page->GetPageWidth();
+  size->height = page->GetPageHeight();
+  return true;
+}
+
+FPDF_EXPORT int FPDF_CALLCONV FPDF_GetPageSizeByIndex(FPDF_DOCUMENT document,
+                                                      int page_index,
+                                                      double* width,
+                                                      double* height) {
+  if (!width || !height)
+    return false;
+
+  FS_SIZEF size;
+  if (!FPDF_GetPageSizeByIndexF(document, page_index, &size))
+    return false;
+
+  *width = size.width;
+  *height = size.height;
   return true;
 }
 
diff --git a/fpdfsdk/fpdf_view_c_api_test.c b/fpdfsdk/fpdf_view_c_api_test.c
index 2b888e4..dce7a23 100644
--- a/fpdfsdk/fpdf_view_c_api_test.c
+++ b/fpdfsdk/fpdf_view_c_api_test.c
@@ -401,8 +401,11 @@
     CHK(FPDF_GetPageBoundingBox);
     CHK(FPDF_GetPageCount);
     CHK(FPDF_GetPageHeight);
+    CHK(FPDF_GetPageHeightF);
     CHK(FPDF_GetPageSizeByIndex);
+    CHK(FPDF_GetPageSizeByIndexF);
     CHK(FPDF_GetPageWidth);
+    CHK(FPDF_GetPageWidthF);
 #ifdef PDF_ENABLE_V8
     CHK(FPDF_GetRecommendedV8Flags);
 #endif
diff --git a/fpdfsdk/fpdf_view_embeddertest.cpp b/fpdfsdk/fpdf_view_embeddertest.cpp
index a74e8f3..fbf3897 100644
--- a/fpdfsdk/fpdf_view_embeddertest.cpp
+++ b/fpdfsdk/fpdf_view_embeddertest.cpp
@@ -397,8 +397,8 @@
   // Now try to access |doc| and make sure it still works.
   ScopedFPDFPage page(FPDF_LoadPage(doc.get(), 0));
   ASSERT_TRUE(page);
-  EXPECT_DOUBLE_EQ(200, FPDF_GetPageWidth(page.get()));
-  EXPECT_DOUBLE_EQ(300, FPDF_GetPageHeight(page.get()));
+  EXPECT_FLOAT_EQ(200.0f, FPDF_GetPageWidthF(page.get()));
+  EXPECT_FLOAT_EQ(300.0f, FPDF_GetPageHeightF(page.get()));
 }
 
 TEST_F(FPDFViewEmbedderTest, Page) {
@@ -406,8 +406,8 @@
   FPDF_PAGE page = LoadPage(0);
   EXPECT_TRUE(page);
 
-  EXPECT_EQ(612.0, FPDF_GetPageWidth(page));
-  EXPECT_EQ(792.0, FPDF_GetPageHeight(page));
+  EXPECT_FLOAT_EQ(612.0f, FPDF_GetPageWidthF(page));
+  EXPECT_FLOAT_EQ(792.0f, FPDF_GetPageHeightF(page));
 
   FS_RECTF rect;
   EXPECT_TRUE(FPDF_GetPageBoundingBox(page, &rect));
@@ -773,8 +773,8 @@
   EXPECT_TRUE(OpenDocument("rectangles.pdf"));
   FPDF_PAGE page = LoadPage(0);
   ASSERT_TRUE(page);
-  const int page_width = static_cast<int>(FPDF_GetPageWidth(page));
-  const int page_height = static_cast<int>(FPDF_GetPageHeight(page));
+  const int page_width = static_cast<int>(FPDF_GetPageWidthF(page));
+  const int page_height = static_cast<int>(FPDF_GetPageHeightF(page));
   EXPECT_EQ(200, page_width);
   EXPECT_EQ(300, page_height);
 
@@ -912,6 +912,41 @@
   UnloadPage(page);
 }
 
+TEST_F(FPDFViewEmbedderTest, FPDF_GetPageSizeByIndexF) {
+  EXPECT_TRUE(OpenDocument("rectangles.pdf"));
+
+  FS_SIZEF size;
+  EXPECT_FALSE(FPDF_GetPageSizeByIndexF(nullptr, 0, &size));
+  EXPECT_FALSE(FPDF_GetPageSizeByIndexF(document(), 0, nullptr));
+
+  // Page -1 doesn't exist.
+  EXPECT_FALSE(FPDF_GetPageSizeByIndexF(document(), -1, &size));
+
+  // Page 1 doesn't exist.
+  EXPECT_FALSE(FPDF_GetPageSizeByIndexF(document(), 1, &size));
+
+  // Page 0 exists.
+  EXPECT_TRUE(FPDF_GetPageSizeByIndexF(document(), 0, &size));
+  EXPECT_FLOAT_EQ(200.0f, size.width);
+  EXPECT_FLOAT_EQ(300.0f, size.height);
+
+  CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document());
+#ifdef PDF_ENABLE_XFA
+  // TODO(tsepez): XFA must obtain this size without parsing.
+  EXPECT_EQ(1u, pDoc->GetParsedPageCountForTesting());
+#else   // PDF_ENABLE_XFA
+  EXPECT_EQ(0u, pDoc->GetParsedPageCountForTesting());
+#endif  // PDF_ENABLE_XFA
+
+  // Double-check against values from when page is actually parsed.
+  FPDF_PAGE page = LoadPage(0);
+  ASSERT_TRUE(page);
+  EXPECT_FLOAT_EQ(size.width, FPDF_GetPageWidthF(page));
+  EXPECT_FLOAT_EQ(size.height, FPDF_GetPageHeightF(page));
+  EXPECT_EQ(1u, pDoc->GetParsedPageCountForTesting());
+  UnloadPage(page);
+}
+
 TEST_F(FPDFViewEmbedderTest, FPDF_GetPageSizeByIndex) {
   EXPECT_TRUE(OpenDocument("rectangles.pdf"));
 
diff --git a/public/fpdfview.h b/public/fpdfview.h
index f7b99f4..e3eb65e 100644
--- a/public/fpdfview.h
+++ b/public/fpdfview.h
@@ -157,6 +157,15 @@
 // Const Pointer to FS_RECTF structure.
 typedef const FS_RECTF* FS_LPCRECTF;
 
+// Rectangle size. Coordinate system agnostic.
+typedef struct FS_SIZEF_ {
+  float width;
+  float height;
+} * FS_LPSIZEF, FS_SIZEF;
+
+// Const Pointer to FS_SIZEF structure.
+typedef const FS_SIZEF* FS_LPCSIZEF;
+
 // Annotation enums.
 typedef int FPDF_ANNOTATION_SUBTYPE;
 typedef int FPDF_ANNOT_APPEARANCEMODE;
@@ -593,6 +602,16 @@
 FPDF_EXPORT FPDF_PAGE FPDF_CALLCONV FPDF_LoadPage(FPDF_DOCUMENT document,
                                                   int page_index);
 
+// Experimental API
+// Function: FPDF_GetPageWidthF
+//          Get page width.
+// Parameters:
+//          page        -   Handle to the page. Returned by FPDF_LoadPage().
+// Return value:
+//          Page width (excluding non-displayable area) measured in points.
+//          One point is 1/72 inch (around 0.3528 mm).
+FPDF_EXPORT float FPDF_CALLCONV FPDF_GetPageWidthF(FPDF_PAGE page);
+
 // Function: FPDF_GetPageWidth
 //          Get page width.
 // Parameters:
@@ -600,8 +619,21 @@
 // Return value:
 //          Page width (excluding non-displayable area) measured in points.
 //          One point is 1/72 inch (around 0.3528 mm).
+// Note:
+//          Prefer FPDF_GetPageWidthF() above. This will be deprecated in the
+//          future.
 FPDF_EXPORT double FPDF_CALLCONV FPDF_GetPageWidth(FPDF_PAGE page);
 
+// Experimental API
+// Function: FPDF_GetPageHeightF
+//          Get page height.
+// Parameters:
+//          page        -   Handle to the page. Returned by FPDF_LoadPage().
+// Return value:
+//          Page height (excluding non-displayable area) measured in points.
+//          One point is 1/72 inch (around 0.3528 mm)
+FPDF_EXPORT float FPDF_CALLCONV FPDF_GetPageHeightF(FPDF_PAGE page);
+
 // Function: FPDF_GetPageHeight
 //          Get page height.
 // Parameters:
@@ -609,6 +641,9 @@
 // Return value:
 //          Page height (excluding non-displayable area) measured in points.
 //          One point is 1/72 inch (around 0.3528 mm)
+// Note:
+//          Prefer FPDF_GetPageHeightF() above. This will be deprecated in the
+//          future.
 FPDF_EXPORT double FPDF_CALLCONV FPDF_GetPageHeight(FPDF_PAGE page);
 
 // Experimental API.
@@ -624,6 +659,21 @@
 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_GetPageBoundingBox(FPDF_PAGE page,
                                                             FS_RECTF* rect);
 
+// Experimental API.
+// Function: FPDF_GetPageSizeByIndexF
+//          Get the size of the page at the given index.
+// Parameters:
+//          document    -   Handle to document. Returned by FPDF_LoadDocument().
+//          page_index  -   Page index, zero for the first page.
+//          size        -   Pointer to a FS_SIZEF to receive the page size.
+//                          (in points).
+// Return value:
+//          Non-zero for success. 0 for error (document or page not found).
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
+FPDF_GetPageSizeByIndexF(FPDF_DOCUMENT document,
+                         int page_index,
+                         FS_SIZEF* size);
+
 // Function: FPDF_GetPageSizeByIndex
 //          Get the size of the page at the given index.
 // Parameters:
@@ -635,6 +685,9 @@
 //                          (in points).
 // Return value:
 //          Non-zero for success. 0 for error (document or page not found).
+// Note:
+//          Prefer FPDF_GetPageSizeByIndexF() above. This will be deprecated in
+//          the future.
 FPDF_EXPORT int FPDF_CALLCONV FPDF_GetPageSizeByIndex(FPDF_DOCUMENT document,
                                                       int page_index,
                                                       double* width,
diff --git a/samples/pdfium_test.cc b/samples/pdfium_test.cc
index 3eb62ca..eb7db5b 100644
--- a/samples/pdfium_test.cc
+++ b/samples/pdfium_test.cc
@@ -694,8 +694,8 @@
   if (!options.scale_factor_as_string.empty())
     std::stringstream(options.scale_factor_as_string) >> scale;
 
-  auto width = static_cast<int>(FPDF_GetPageWidth(page) * scale);
-  auto height = static_cast<int>(FPDF_GetPageHeight(page) * scale);
+  auto width = static_cast<int>(FPDF_GetPageWidthF(page) * scale);
+  auto height = static_cast<int>(FPDF_GetPageHeightF(page) * scale);
   int alpha = FPDFPage_HasTransparency(page) ? 1 : 0;
   ScopedFPDFBitmap bitmap(FPDFBitmap_Create(width, height, alpha));
 
diff --git a/samples/pdfium_test_write_helper.cc b/samples/pdfium_test_write_helper.cc
index 7c1f782..356bb08 100644
--- a/samples/pdfium_test_write_helper.cc
+++ b/samples/pdfium_test_write_helper.cc
@@ -466,8 +466,8 @@
 
   HDC dc = CreateEnhMetaFileA(nullptr, filename, nullptr, nullptr);
 
-  int width = static_cast<int>(FPDF_GetPageWidth(page));
-  int height = static_cast<int>(FPDF_GetPageHeight(page));
+  int width = static_cast<int>(FPDF_GetPageWidthF(page));
+  int height = static_cast<int>(FPDF_GetPageHeightF(page));
   HRGN rgn = CreateRectRgn(0, 0, width, height);
   SelectClipRgn(dc, rgn);
   DeleteObject(rgn);
@@ -491,8 +491,8 @@
 
   HDC dc = CreateEnhMetaFileA(nullptr, nullptr, nullptr, nullptr);
 
-  int width = static_cast<int>(FPDF_GetPageWidth(page));
-  int height = static_cast<int>(FPDF_GetPageHeight(page));
+  int width = static_cast<int>(FPDF_GetPageWidthF(page));
+  int height = static_cast<int>(FPDF_GetPageHeightF(page));
   FPDF_RenderPage(dc, page, 0, 0, width, height, 0, FPDF_ANNOT | FPDF_PRINTING);
 
   HENHMETAFILE emf = CloseEnhMetaFile(dc);
diff --git a/testing/embedder_test.cpp b/testing/embedder_test.cpp
index c999732..265b33f 100644
--- a/testing/embedder_test.cpp
+++ b/testing/embedder_test.cpp
@@ -379,8 +379,8 @@
 ScopedFPDFBitmap EmbedderTest::RenderPageWithFlags(FPDF_PAGE page,
                                                    FPDF_FORMHANDLE handle,
                                                    int flags) {
-  int width = static_cast<int>(FPDF_GetPageWidth(page));
-  int height = static_cast<int>(FPDF_GetPageHeight(page));
+  int width = static_cast<int>(FPDF_GetPageWidthF(page));
+  int height = static_cast<int>(FPDF_GetPageHeightF(page));
   int alpha = FPDFPage_HasTransparency(page) ? 1 : 0;
   ScopedFPDFBitmap bitmap(FPDFBitmap_Create(width, height, alpha));
   FPDF_DWORD fill_color = alpha ? 0x00000000 : 0xFFFFFFFF;
@@ -401,8 +401,8 @@
                                                             int flags) {
   HDC dc = CreateEnhMetaFileA(nullptr, nullptr, nullptr, nullptr);
 
-  int width = static_cast<int>(FPDF_GetPageWidth(page));
-  int height = static_cast<int>(FPDF_GetPageHeight(page));
+  int width = static_cast<int>(FPDF_GetPageWidthF(page));
+  int height = static_cast<int>(FPDF_GetPageHeightF(page));
   HRGN rgn = CreateRectRgn(0, 0, width, height);
   SelectClipRgn(dc, rgn);
   DeleteObject(rgn);
diff --git a/testing/fuzzers/pdfium_fuzzer_helper.cc b/testing/fuzzers/pdfium_fuzzer_helper.cc
index 27e0292..266666d 100644
--- a/testing/fuzzers/pdfium_fuzzer_helper.cc
+++ b/testing/fuzzers/pdfium_fuzzer_helper.cc
@@ -219,8 +219,8 @@
   FORM_DoPageAAction(page.get(), form, FPDFPAGE_AACTION_OPEN);
 
   const double scale = 1.0;
-  int width = static_cast<int>(FPDF_GetPageWidth(page.get()) * scale);
-  int height = static_cast<int>(FPDF_GetPageHeight(page.get()) * scale);
+  int width = static_cast<int>(FPDF_GetPageWidthF(page.get()) * scale);
+  int height = static_cast<int>(FPDF_GetPageHeightF(page.get()) * scale);
   ScopedFPDFBitmap bitmap(FPDFBitmap_Create(width, height, 0));
   if (bitmap) {
     FPDFBitmap_FillRect(bitmap.get(), 0, 0, width, height, 0xFFFFFFFF);