Add FPDFDest_GetLocationInPage API

Add an API to get the value of the /XYZ destination parameter.

This CL was originally from https://codereview.chromium.org/1960193003/ by
halcanary@.

Review-Url: https://codereview.chromium.org/2481743004
diff --git a/fpdfsdk/fpdfdoc.cpp b/fpdfsdk/fpdfdoc.cpp
index 5d11359..401b3e4 100644
--- a/fpdfsdk/fpdfdoc.cpp
+++ b/fpdfsdk/fpdfdoc.cpp
@@ -13,6 +13,7 @@
 #include "core/fpdfapi/parser/cpdf_document.h"
 #include "core/fpdfdoc/cpdf_bookmark.h"
 #include "core/fpdfdoc/cpdf_bookmarktree.h"
+#include "core/fpdfdoc/cpdf_dest.h"
 #include "fpdfsdk/fsdk_define.h"
 #include "third_party/base/stl_util.h"
 
@@ -211,6 +212,32 @@
   return dest.GetPageIndex(pDoc);
 }
 
+DLLEXPORT FPDF_BOOL STDCALL FPDFDest_GetLocationInPage(FPDF_DEST pDict,
+                                                       FPDF_BOOL* hasXVal,
+                                                       FPDF_BOOL* hasYVal,
+                                                       FPDF_BOOL* hasZoomVal,
+                                                       FS_FLOAT* x,
+                                                       FS_FLOAT* y,
+                                                       FS_FLOAT* zoom) {
+  if (!pDict)
+    return false;
+
+  std::unique_ptr<CPDF_Dest> dest(
+      new CPDF_Dest(static_cast<CPDF_Object*>(pDict)));
+
+  // FPDF_BOOL is an int, GetXYZ expects bools.
+  bool bHasX;
+  bool bHasY;
+  bool bHasZoom;
+  if (!dest->GetXYZ(&bHasX, &bHasY, &bHasZoom, x, y, zoom))
+    return false;
+
+  *hasXVal = bHasX;
+  *hasYVal = bHasY;
+  *hasZoomVal = bHasZoom;
+  return true;
+}
+
 DLLEXPORT FPDF_LINK STDCALL FPDFLink_GetLinkAtPoint(FPDF_PAGE page,
                                                     double x,
                                                     double y) {
diff --git a/fpdfsdk/fpdfdoc_embeddertest.cpp b/fpdfsdk/fpdfdoc_embeddertest.cpp
index 39b36c4..1616093 100644
--- a/fpdfsdk/fpdfdoc_embeddertest.cpp
+++ b/fpdfsdk/fpdfdoc_embeddertest.cpp
@@ -42,6 +42,31 @@
   EXPECT_EQ(0U, FPDFDest_GetPageIndex(document(), dest));
 }
 
+TEST_F(FPDFDocEmbeddertest, DestGetLocationInPage) {
+  EXPECT_TRUE(OpenDocument("named_dests.pdf"));
+
+  // NULL FPDF_DEST case.
+  EXPECT_EQ(0U, FPDFDest_GetPageIndex(document(), nullptr));
+
+  FPDF_DEST dest = FPDF_GetNamedDestByName(document(), "First");
+  EXPECT_TRUE(dest);
+
+  FPDF_BOOL hasX;
+  FPDF_BOOL hasY;
+  FPDF_BOOL hasZoom;
+  FS_FLOAT x;
+  FS_FLOAT y;
+  FS_FLOAT zoom;
+  EXPECT_TRUE(
+      FPDFDest_GetLocationInPage(dest, &hasX, &hasY, &hasZoom, &x, &y, &zoom));
+  EXPECT_TRUE(hasX);
+  EXPECT_TRUE(hasY);
+  EXPECT_TRUE(hasZoom);
+  EXPECT_EQ(0, x);
+  EXPECT_EQ(0, y);
+  EXPECT_EQ(1, zoom);
+}
+
 TEST_F(FPDFDocEmbeddertest, ActionGetFilePath) {
   EXPECT_TRUE(OpenDocument("launch_action.pdf"));
 
diff --git a/fpdfsdk/fpdfdoc_unittest.cpp b/fpdfsdk/fpdfdoc_unittest.cpp
index 39e81d5..fc90257 100644
--- a/fpdfsdk/fpdfdoc_unittest.cpp
+++ b/fpdfsdk/fpdfdoc_unittest.cpp
@@ -8,12 +8,15 @@
 #include <vector>
 
 #include "core/fpdfapi/cpdf_modulemgr.h"
+#include "core/fpdfapi/parser/cpdf_array.h"
 #include "core/fpdfapi/parser/cpdf_document.h"
 #include "core/fpdfapi/parser/cpdf_name.h"
+#include "core/fpdfapi/parser/cpdf_null.h"
 #include "core/fpdfapi/parser/cpdf_number.h"
 #include "core/fpdfapi/parser/cpdf_parser.h"
 #include "core/fpdfapi/parser/cpdf_reference.h"
 #include "core/fpdfapi/parser/cpdf_string.h"
+#include "core/fpdfdoc/cpdf_dest.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/test_support.h"
 #include "third_party/base/ptr_util.h"
@@ -230,3 +233,41 @@
     EXPECT_EQ(bookmarks[3].obj, FPDFBookmark_Find(m_pDoc.get(), title.get()));
   }
 }
+
+TEST_F(PDFDocTest, GetLocationInPage) {
+  auto array = pdfium::MakeUnique<CPDF_Array>();
+  array->AddInteger(0);  // Page Index.
+  array->AddName("XYZ");
+  array->AddNumber(4);  // X
+  array->AddNumber(5);  // Y
+  array->AddNumber(6);  // Zoom.
+
+  FPDF_BOOL hasX;
+  FPDF_BOOL hasY;
+  FPDF_BOOL hasZoom;
+  FS_FLOAT x;
+  FS_FLOAT y;
+  FS_FLOAT zoom;
+
+  EXPECT_TRUE(FPDFDest_GetLocationInPage(array.get(), &hasX, &hasY, &hasZoom,
+                                         &x, &y, &zoom));
+  EXPECT_TRUE(hasX);
+  EXPECT_TRUE(hasY);
+  EXPECT_TRUE(hasZoom);
+  EXPECT_EQ(4, x);
+  EXPECT_EQ(5, y);
+  EXPECT_EQ(6, zoom);
+
+  array->SetAt(2, new CPDF_Null);
+  array->SetAt(3, new CPDF_Null);
+  array->SetAt(4, new CPDF_Null);
+  EXPECT_TRUE(FPDFDest_GetLocationInPage(array.get(), &hasX, &hasY, &hasZoom,
+                                         &x, &y, &zoom));
+  EXPECT_FALSE(hasX);
+  EXPECT_FALSE(hasY);
+  EXPECT_FALSE(hasZoom);
+
+  array = pdfium::MakeUnique<CPDF_Array>();
+  EXPECT_FALSE(FPDFDest_GetLocationInPage(array.get(), &hasX, &hasY, &hasZoom,
+                                          &x, &y, &zoom));
+}
diff --git a/fpdfsdk/fpdfview_c_api_test.c b/fpdfsdk/fpdfview_c_api_test.c
index 4847180..a48ddb9 100644
--- a/fpdfsdk/fpdfview_c_api_test.c
+++ b/fpdfsdk/fpdfview_c_api_test.c
@@ -54,6 +54,7 @@
     CHK(FPDFAction_GetFilePath);
     CHK(FPDFAction_GetURIPath);
     CHK(FPDFDest_GetPageIndex);
+    CHK(FPDFDest_GetLocationInPage);
     CHK(FPDFLink_GetLinkAtPoint);
     CHK(FPDFLink_GetLinkZOrderAtPoint);
     CHK(FPDFLink_GetDest);