From de3f3fc5e16a2ee4fad2bdc0cda9e2ce73fd4fe3 Mon Sep 17 00:00:00 2001 From: Henrique Nakashima Date: Thu, 4 Jan 2018 11:54:18 -0500 Subject: Open FPDFDest_GetView API. FPDFDest_GetView returns the view fit type and the parameters of the view for a given destination. This is useful to have more precise internal links and bookmarks that are able to manipulate the viewport position and zoom level to focus on the part of the PDF that it links to. Bug: 55776, 535978, 748852 Change-Id: Ibf7df40a852030d75ec78cec7662380319569850 Reviewed-on: https://pdfium-review.googlesource.com/21790 Commit-Queue: Henrique Nakashima Reviewed-by: Ryan Harrison --- core/fpdfdoc/cpdf_dest.cpp | 26 +++++++++++++++--- core/fpdfdoc/cpdf_dest.h | 4 +++ fpdfsdk/fpdfdoc.cpp | 24 ++++++++++++++++ fpdfsdk/fpdfdoc_embeddertest.cpp | 59 ++++++++++++++++++++++++++++++++++++++++ fpdfsdk/fpdfview_c_api_test.c | 1 + public/fpdf_doc.h | 27 ++++++++++++++++++ 6 files changed, 137 insertions(+), 4 deletions(-) diff --git a/core/fpdfdoc/cpdf_dest.cpp b/core/fpdfdoc/cpdf_dest.cpp index ebe3834e91..cb15bf1c33 100644 --- a/core/fpdfdoc/cpdf_dest.cpp +++ b/core/fpdfdoc/cpdf_dest.cpp @@ -6,6 +6,8 @@ #include "core/fpdfdoc/cpdf_dest.h" +#include + #include "core/fpdfapi/parser/cpdf_array.h" #include "core/fpdfapi/parser/cpdf_document.h" #include "core/fpdfapi/parser/cpdf_name.h" @@ -13,8 +15,14 @@ namespace { -const char* const g_sZoomModes[] = {"XYZ", "Fit", "FitH", "FitV", "FitR", - "FitB", "FitBH", "FitBV", nullptr}; +// These arrays are indexed by the PDFDEST_VIEW_* constants. + +// Last element is a sentinel. +const char* const g_sZoomModes[] = {"Unknown", "XYZ", "Fit", "FitH", + "FitV", "FitR", "FitB", "FitBH", + "FitBV", nullptr}; + +const int g_sZoomModeMaxParamCount[] = {0, 3, 0, 1, 1, 4, 0, 1, 1, 0}; } // namespace @@ -66,9 +74,9 @@ int CPDF_Dest::GetZoomMode() { return 0; ByteString mode = pObj->GetString(); - for (int i = 0; g_sZoomModes[i]; ++i) { + for (int i = 1; g_sZoomModes[i]; ++i) { if (mode == g_sZoomModes[i]) - return i + 1; + return i; } return 0; @@ -121,6 +129,16 @@ bool CPDF_Dest::GetXYZ(bool* pHasX, return true; } +unsigned int CPDF_Dest::GetNumParams() { + CPDF_Array* pArray = ToArray(m_pObj.Get()); + if (!pArray || pArray->GetCount() < 2) + return 0; + + size_t maxParamsForFitType = g_sZoomModeMaxParamCount[GetZoomMode()]; + size_t numParamsInArray = pArray->GetCount() - 2; + return std::min(maxParamsForFitType, numParamsInArray); +} + float CPDF_Dest::GetParam(int index) { CPDF_Array* pArray = ToArray(m_pObj.Get()); return pArray ? pArray->GetNumberAt(2 + index) : 0; diff --git a/core/fpdfdoc/cpdf_dest.h b/core/fpdfdoc/cpdf_dest.h index 2836ebb471..4959901972 100644 --- a/core/fpdfdoc/cpdf_dest.h +++ b/core/fpdfdoc/cpdf_dest.h @@ -25,7 +25,11 @@ class CPDF_Dest { ByteString GetRemoteName(); int GetPageIndex(CPDF_Document* pDoc); uint32_t GetPageObjNum(); + + // Returns the zoom mode, as one of the PDFDEST_VIEW_* values in fpdf_doc.h. int GetZoomMode(); + + unsigned int GetNumParams(); float GetParam(int index); bool GetXYZ(bool* pHasX, diff --git a/fpdfsdk/fpdfdoc.cpp b/fpdfsdk/fpdfdoc.cpp index 4d2942fb31..51a1c61e77 100644 --- a/fpdfsdk/fpdfdoc.cpp +++ b/fpdfsdk/fpdfdoc.cpp @@ -210,6 +210,30 @@ FPDFDest_GetPageIndex(FPDF_DOCUMENT document, FPDF_DEST pDict) { return dest.GetPageIndex(pDoc); } +FPDF_EXPORT unsigned long FPDF_CALLCONV +FPDFDest_GetView(FPDF_DOCUMENT document, + FPDF_DEST pDict, + unsigned long* outNumParams, + FS_FLOAT* outParams) { + if (!pDict) { + *outNumParams = 0; + return 0; + } + + CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document); + if (!pDoc) { + *outNumParams = 0; + return 0; + } + + CPDF_Dest dest(static_cast(pDict)); + + *outNumParams = dest.GetNumParams(); + for (unsigned long i = 0; i < *outNumParams; ++i) + outParams[i] = dest.GetParam(i); + return dest.GetZoomMode(); +} + FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFDest_GetLocationInPage(FPDF_DEST pDict, FPDF_BOOL* hasXVal, diff --git a/fpdfsdk/fpdfdoc_embeddertest.cpp b/fpdfsdk/fpdfdoc_embeddertest.cpp index c691a17a11..24414a1c33 100644 --- a/fpdfsdk/fpdfdoc_embeddertest.cpp +++ b/fpdfsdk/fpdfdoc_embeddertest.cpp @@ -42,6 +42,65 @@ TEST_F(FPDFDocEmbeddertest, DestGetPageIndex) { EXPECT_EQ(0U, FPDFDest_GetPageIndex(document(), dest)); } +TEST_F(FPDFDocEmbeddertest, DestGetView) { + EXPECT_TRUE(OpenDocument("named_dests.pdf")); + + unsigned long numParams; + FS_FLOAT params[4]; + + numParams = 42; + std::fill_n(params, 4, 42.4242f); + EXPECT_EQ(static_cast(PDFDEST_VIEW_UNKNOWN_MODE), + FPDFDest_GetView(document(), nullptr, &numParams, params)); + EXPECT_EQ(0U, numParams); + EXPECT_FLOAT_EQ(42.4242f, params[0]); + + numParams = 42; + std::fill_n(params, 4, 42.4242f); + FPDF_DEST dest = FPDF_GetNamedDestByName(document(), "First"); + EXPECT_TRUE(dest); + EXPECT_EQ(static_cast(PDFDEST_VIEW_XYZ), + FPDFDest_GetView(document(), dest, &numParams, params)); + EXPECT_EQ(3U, numParams); + EXPECT_FLOAT_EQ(0, params[0]); + EXPECT_FLOAT_EQ(0, params[1]); + EXPECT_FLOAT_EQ(1, params[2]); + EXPECT_FLOAT_EQ(42.4242f, params[3]); + + numParams = 42; + std::fill_n(params, 4, 42.4242f); + dest = FPDF_GetNamedDestByName(document(), "Next"); + EXPECT_TRUE(dest); + EXPECT_EQ(static_cast(PDFDEST_VIEW_FIT), + FPDFDest_GetView(document(), dest, &numParams, params)); + EXPECT_EQ(0U, numParams); + EXPECT_FLOAT_EQ(42.4242f, params[0]); + + numParams = 42; + std::fill_n(params, 4, 42.4242f); + dest = FPDF_GetNamedDestByName(document(), "FirstAlternate"); + EXPECT_TRUE(dest); + EXPECT_EQ(static_cast(PDFDEST_VIEW_XYZ), + FPDFDest_GetView(document(), dest, &numParams, params)); + EXPECT_EQ(3U, numParams); + EXPECT_FLOAT_EQ(200, params[0]); + EXPECT_FLOAT_EQ(400, params[1]); + EXPECT_FLOAT_EQ(800, params[2]); + EXPECT_FLOAT_EQ(42.4242f, params[3]); + + numParams = 42; + std::fill_n(params, 4, 42.4242f); + dest = FPDF_GetNamedDestByName(document(), "LastAlternate"); + EXPECT_TRUE(dest); + EXPECT_EQ(static_cast(PDFDEST_VIEW_XYZ), + FPDFDest_GetView(document(), dest, &numParams, params)); + EXPECT_EQ(3U, numParams); + EXPECT_FLOAT_EQ(0, params[0]); + EXPECT_FLOAT_EQ(0, params[1]); + EXPECT_FLOAT_EQ(-200, params[2]); + EXPECT_FLOAT_EQ(42.4242f, params[3]); +} + TEST_F(FPDFDocEmbeddertest, DestGetLocationInPage) { EXPECT_TRUE(OpenDocument("named_dests.pdf")); diff --git a/fpdfsdk/fpdfview_c_api_test.c b/fpdfsdk/fpdfview_c_api_test.c index de4fa1c564..199c383ae5 100644 --- a/fpdfsdk/fpdfview_c_api_test.c +++ b/fpdfsdk/fpdfview_c_api_test.c @@ -107,6 +107,7 @@ int CheckPDFiumCApi() { CHK(FPDFAction_GetURIPath); CHK(FPDFDest_GetPageIndex); CHK(FPDFDest_GetLocationInPage); + CHK(FPDFDest_GetView); CHK(FPDFLink_GetLinkAtPoint); CHK(FPDFLink_GetLinkZOrderAtPoint); CHK(FPDFLink_GetDest); diff --git a/public/fpdf_doc.h b/public/fpdf_doc.h index 0f87361b38..93efa7ae98 100644 --- a/public/fpdf_doc.h +++ b/public/fpdf_doc.h @@ -25,6 +25,17 @@ extern "C" { // Launch an application or open a file. #define PDFACTION_LAUNCH 4 +// View destination fit types. See pdfmark reference v9, page 48. +#define PDFDEST_VIEW_UNKNOWN_MODE 0 +#define PDFDEST_VIEW_XYZ 1 +#define PDFDEST_VIEW_FIT 2 +#define PDFDEST_VIEW_FITH 3 +#define PDFDEST_VIEW_FITV 4 +#define PDFDEST_VIEW_FITR 5 +#define PDFDEST_VIEW_FITB 6 +#define PDFDEST_VIEW_FITBH 7 +#define PDFDEST_VIEW_FITBV 8 + typedef struct _FS_QUADPOINTSF { FS_FLOAT x1; FS_FLOAT y1; @@ -175,6 +186,22 @@ FPDFAction_GetURIPath(FPDF_DOCUMENT document, FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFDest_GetPageIndex(FPDF_DOCUMENT document, FPDF_DEST dest); +// Get the view (fit type) specified by |dest|. +// Experimental API. Subject to change. +// +// document - handle to the document. +// dest - handle to the destination. +// outNumParams - buffer to write the number of view parameters. +// outParams - buffer to write the view parameters. Must be at least 4 +// FS_FLOATs long. +// Returns one of the PDFDEST_VIEW_* constants, PDFDEST_VIEW_UNKNOWN_MODE if +// |dest| does not specify a view. +FPDF_EXPORT unsigned long FPDF_CALLCONV +FPDFDest_GetView(FPDF_DOCUMENT document, + FPDF_DEST dest, + unsigned long* outNumParams, + FS_FLOAT* outParams); + // Get the (x, y, zoom) location of |dest| in the destination page, if the // destination is in [page /XYZ x y zoom] syntax. // -- cgit v1.2.3