From 36eed87d19e741be9909500c45dd12e50ff6a1ab Mon Sep 17 00:00:00 2001 From: Miklos Vajna Date: Wed, 20 Sep 2017 22:52:43 +0200 Subject: Add FPDFPath_GetPoint() API Combined with the previously added FPDFPath_CountPoint(), this allows getting the coordinates of all points of a path. Change-Id: Ic969723d4b01ee427498d38ce323c74147b87a9c Reviewed-on: https://pdfium-review.googlesource.com/14111 Commit-Queue: dsinclair Reviewed-by: dsinclair --- fpdfsdk/fpdfedit_embeddertest.cpp | 69 +++++++++++++++++++++++++++++++++++++++ fpdfsdk/fpdfeditpath.cpp | 46 ++++++++++++++++++++++++++ fpdfsdk/fpdfview.cpp | 4 +++ fpdfsdk/fpdfview_c_api_test.c | 4 +++ fpdfsdk/fsdk_define.h | 3 ++ public/fpdf_edit.h | 46 ++++++++++++++++++++++++++ public/fpdfview.h | 1 + 7 files changed, 173 insertions(+) diff --git a/fpdfsdk/fpdfedit_embeddertest.cpp b/fpdfsdk/fpdfedit_embeddertest.cpp index ca2a457147..6826317ef2 100644 --- a/fpdfsdk/fpdfedit_embeddertest.cpp +++ b/fpdfsdk/fpdfedit_embeddertest.cpp @@ -259,6 +259,39 @@ TEST_F(FPDFEditEmbeddertest, AddPaths) { // Make sure the path has 5 points (1 FXPT_TYPE::MoveTo and 4 // FXPT_TYPE::LineTo). ASSERT_EQ(5, FPDFPath_CountPoint(green_rect)); + // Verify actual coordinates. + FPDF_PATHSEGMENT segment = FPDFPath_GetPathSegment(green_rect, 0); + float x; + float y; + EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y)); + EXPECT_EQ(100, x); + EXPECT_EQ(100, y); + EXPECT_EQ(FPDF_SEGMENT_MOVETO, FPDFPathSegment_GetType(segment)); + EXPECT_FALSE(FPDFPathSegment_GetClose(segment)); + segment = FPDFPath_GetPathSegment(green_rect, 1); + EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y)); + EXPECT_EQ(100, x); + EXPECT_EQ(140, y); + EXPECT_EQ(FPDF_SEGMENT_LINETO, FPDFPathSegment_GetType(segment)); + EXPECT_FALSE(FPDFPathSegment_GetClose(segment)); + segment = FPDFPath_GetPathSegment(green_rect, 2); + EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y)); + EXPECT_EQ(140, x); + EXPECT_EQ(140, y); + EXPECT_EQ(FPDF_SEGMENT_LINETO, FPDFPathSegment_GetType(segment)); + EXPECT_FALSE(FPDFPathSegment_GetClose(segment)); + segment = FPDFPath_GetPathSegment(green_rect, 3); + EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y)); + EXPECT_EQ(140, x); + EXPECT_EQ(100, y); + EXPECT_EQ(FPDF_SEGMENT_LINETO, FPDFPathSegment_GetType(segment)); + EXPECT_FALSE(FPDFPathSegment_GetClose(segment)); + segment = FPDFPath_GetPathSegment(green_rect, 4); + EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y)); + EXPECT_EQ(100, x); + EXPECT_EQ(100, y); + EXPECT_EQ(FPDF_SEGMENT_LINETO, FPDFPathSegment_GetType(segment)); + EXPECT_TRUE(FPDFPathSegment_GetClose(segment)); EXPECT_TRUE(FPDFPath_SetDrawMode(green_rect, FPDF_FILLMODE_WINDING, 0)); FPDFPage_InsertObject(page, green_rect); @@ -277,6 +310,27 @@ TEST_F(FPDFEditEmbeddertest, AddPaths) { // Make sure the path has 3 points (1 FXPT_TYPE::MoveTo and 2 // FXPT_TYPE::LineTo). ASSERT_EQ(3, FPDFPath_CountPoint(black_path)); + // Verify actual coordinates. + segment = FPDFPath_GetPathSegment(black_path, 0); + EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y)); + EXPECT_EQ(400, x); + EXPECT_EQ(100, y); + EXPECT_EQ(FPDF_SEGMENT_MOVETO, FPDFPathSegment_GetType(segment)); + EXPECT_FALSE(FPDFPathSegment_GetClose(segment)); + segment = FPDFPath_GetPathSegment(black_path, 1); + EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y)); + EXPECT_EQ(400, x); + EXPECT_EQ(200, y); + EXPECT_EQ(FPDF_SEGMENT_LINETO, FPDFPathSegment_GetType(segment)); + EXPECT_FALSE(FPDFPathSegment_GetClose(segment)); + segment = FPDFPath_GetPathSegment(black_path, 2); + EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y)); + EXPECT_EQ(300, x); + EXPECT_EQ(100, y); + EXPECT_EQ(FPDF_SEGMENT_LINETO, FPDFPathSegment_GetType(segment)); + EXPECT_TRUE(FPDFPathSegment_GetClose(segment)); + // Make sure out of bounds index access fails properly. + EXPECT_EQ(nullptr, FPDFPath_GetPathSegment(black_path, 3)); FPDFPage_InsertObject(page, black_path); page_bitmap = RenderPage(page); @@ -317,6 +371,21 @@ TEST_F(FPDFEditEmbeddertest, PathsPoints) { // This should fail gracefully, even if path is NULL. ASSERT_EQ(-1, FPDFPath_CountPoint(nullptr)); + // FPDFPath_GetPathSegment() with a non-path. + ASSERT_EQ(nullptr, FPDFPath_GetPathSegment(img, 0)); + // FPDFPath_GetPathSegment() with a NULL path. + ASSERT_EQ(nullptr, FPDFPath_GetPathSegment(nullptr, 0)); + float x; + float y; + // FPDFPathSegment_GetPoint() with a NULL segment. + EXPECT_FALSE(FPDFPathSegment_GetPoint(nullptr, &x, &y)); + + // FPDFPathSegment_GetType() with a NULL segment. + ASSERT_EQ(FPDF_SEGMENT_UNKNOWN, FPDFPathSegment_GetType(nullptr)); + + // FPDFPathSegment_GetClose() with a NULL segment. + EXPECT_FALSE(FPDFPathSegment_GetClose(nullptr)); + FPDFPageObj_Destroy(img); } diff --git a/fpdfsdk/fpdfeditpath.cpp b/fpdfsdk/fpdfeditpath.cpp index 164ab7015f..a91dfdb421 100644 --- a/fpdfsdk/fpdfeditpath.cpp +++ b/fpdfsdk/fpdfeditpath.cpp @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include + #include "public/fpdf_edit.h" #include "core/fpdfapi/page/cpdf_path.h" @@ -26,6 +28,13 @@ static_assert(CFX_GraphStateData::LineJoinRound == FPDF_LINEJOIN_ROUND, static_assert(CFX_GraphStateData::LineJoinBevel == FPDF_LINEJOIN_BEVEL, "CFX_GraphStateData::LineJoinBevel value mismatch"); +static_assert(static_cast(FXPT_TYPE::LineTo) == FPDF_SEGMENT_LINETO, + "FXPT_TYPE::LineTo value mismatch"); +static_assert(static_cast(FXPT_TYPE::BezierTo) == FPDF_SEGMENT_BEZIERTO, + "FXPT_TYPE::BezierTo value mismatch"); +static_assert(static_cast(FXPT_TYPE::MoveTo) == FPDF_SEGMENT_MOVETO, + "FXPT_TYPE::MoveTo value mismatch"); + FPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV FPDFPageObj_CreateNewPath(float x, float y) { auto pPathObj = pdfium::MakeUnique(); @@ -125,6 +134,16 @@ FPDF_EXPORT int FPDF_CALLCONV FPDFPath_CountPoint(FPDF_PAGEOBJECT path) { return pdfium::CollectionSize(pPathObj->m_Path.GetPoints()); } +FPDF_EXPORT FPDF_PATHSEGMENT FPDF_CALLCONV +FPDFPath_GetPathSegment(FPDF_PAGEOBJECT path, int index) { + auto* pPathObj = CPDFPathObjectFromFPDFPageObject(path); + if (!pPathObj) + return nullptr; + + const std::vector& points = pPathObj->m_Path.GetPoints(); + return pdfium::IndexInBounds(points, index) ? &points[index] : nullptr; +} + FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPath_MoveTo(FPDF_PAGEOBJECT path, float x, float y) { @@ -229,3 +248,30 @@ FPDF_EXPORT void FPDF_CALLCONV FPDFPath_SetLineCap(FPDF_PAGEOBJECT path, pPathObj->m_GraphState.SetLineCap(lineCap); pPathObj->SetDirty(true); } + +FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV +FPDFPathSegment_GetPoint(FPDF_PATHSEGMENT segment, float* x, float* y) { + auto* pPathPoint = FXPathPointFromFPDFPathSegment(segment); + if (!pPathPoint || !x || !y) + return false; + + *x = pPathPoint->m_Point.x; + *y = pPathPoint->m_Point.y; + + return true; +} + +FPDF_EXPORT int FPDF_CALLCONV +FPDFPathSegment_GetType(FPDF_PATHSEGMENT segment) { + auto* pPathPoint = FXPathPointFromFPDFPathSegment(segment); + + return pPathPoint ? static_cast(pPathPoint->m_Type) + : FPDF_SEGMENT_UNKNOWN; +} + +FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV +FPDFPathSegment_GetClose(FPDF_PATHSEGMENT segment) { + auto* pPathPoint = FXPathPointFromFPDFPathSegment(segment); + + return pPathPoint ? pPathPoint->m_CloseFigure : false; +} diff --git a/fpdfsdk/fpdfview.cpp b/fpdfsdk/fpdfview.cpp index 9e9c31ddc9..c52c598783 100644 --- a/fpdfsdk/fpdfview.cpp +++ b/fpdfsdk/fpdfview.cpp @@ -357,6 +357,10 @@ CFX_DIBitmap* CFXBitmapFromFPDFBitmap(FPDF_BITMAP bitmap) { return static_cast(bitmap); } +const FX_PATHPOINT* FXPathPointFromFPDFPathSegment(FPDF_PATHSEGMENT segment) { + return static_cast(segment); +} + unsigned long Utf16EncodeMaybeCopyAndReturnLength(const WideString& text, void* buffer, unsigned long buflen) { diff --git a/fpdfsdk/fpdfview_c_api_test.c b/fpdfsdk/fpdfview_c_api_test.c index 415543dbe2..b3fe303eac 100644 --- a/fpdfsdk/fpdfview_c_api_test.c +++ b/fpdfsdk/fpdfview_c_api_test.c @@ -149,6 +149,10 @@ int CheckPDFiumCApi() { CHK(FPDFPath_SetFillColor); CHK(FPDFPath_GetFillColor); CHK(FPDFPath_CountPoint); + CHK(FPDFPath_GetPathSegment); + CHK(FPDFPathSegment_GetPoint); + CHK(FPDFPathSegment_GetType); + CHK(FPDFPathSegment_GetClose); CHK(FPDFPath_MoveTo); CHK(FPDFPath_LineTo); CHK(FPDFPath_BezierTo); diff --git a/fpdfsdk/fsdk_define.h b/fpdfsdk/fsdk_define.h index e58ddb1a49..68ba585c0a 100644 --- a/fpdfsdk/fsdk_define.h +++ b/fpdfsdk/fsdk_define.h @@ -28,6 +28,7 @@ class CPDF_PageRenderContext; class CPDF_PathObject; class CPDF_Stream; class IFSDK_PAUSE_Adapter; +class FX_PATHPOINT; // Layering prevents fxcrt from knowing about FPDF_FILEACCESS, so this can't // be a static method of IFX_SeekableReadStream. @@ -74,6 +75,8 @@ ByteString CFXByteStringFromFPDFWideString(FPDF_WIDESTRING wide_string); CFX_DIBitmap* CFXBitmapFromFPDFBitmap(FPDF_BITMAP bitmap); +const FX_PATHPOINT* FXPathPointFromFPDFPathSegment(FPDF_PATHSEGMENT segment); + unsigned long Utf16EncodeMaybeCopyAndReturnLength(const WideString& text, void* buffer, unsigned long buflen); diff --git a/public/fpdf_edit.h b/public/fpdf_edit.h index 9ee11cb5ec..d73a740efd 100644 --- a/public/fpdf_edit.h +++ b/public/fpdf_edit.h @@ -42,6 +42,12 @@ #define FPDF_PAGEOBJ_SHADING 4 #define FPDF_PAGEOBJ_FORM 5 +// The path segment constants. +#define FPDF_SEGMENT_UNKNOWN -1 +#define FPDF_SEGMENT_LINETO 0 +#define FPDF_SEGMENT_BEZIERTO 1 +#define FPDF_SEGMENT_MOVETO 2 + #define FPDF_FILLMODE_ALTERNATE 1 #define FPDF_FILLMODE_WINDING 2 @@ -552,6 +558,7 @@ FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPath_GetFillColor(FPDF_PAGEOBJECT path, unsigned int* B, unsigned int* A); +// Experimental API. // Get number of point objects inside |path|. // // path - handle to a path. @@ -562,6 +569,45 @@ FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPath_GetFillColor(FPDF_PAGEOBJECT path, // Returns the number of objects in |path| or -1 on failure. FPDF_EXPORT int FPDF_CALLCONV FPDFPath_CountPoint(FPDF_PAGEOBJECT path); +// Experimental API. +// Get segment in |path| at |index|. +// +// path - handle to a path. +// index - the index of a segment. +// +// Returns the handle to the segment, or NULL on faiure. +FPDF_EXPORT FPDF_PATHSEGMENT FPDF_CALLCONV +FPDFPath_GetPathSegment(FPDF_PAGEOBJECT path, int index); + +// Experimental API. +// Get coordinates of |segment|. +// +// segment - handle to a segment. +// x - the horizontal position of the segment. +// y - the vertical position of the segment. +// +// Returns TRUE on success, otherwise |x| and |y| is not set. +FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV +FPDFPathSegment_GetPoint(FPDF_PATHSEGMENT segment, float* x, float* y); + +// Experimental API. +// Get type of |segment|. +// +// segment - handle to a segment. +// +// Returns one of the FPDF_SEGMENT_* values on success, +// FPDF_SEGMENT_UNKNOWN on error. +FPDF_EXPORT int FPDF_CALLCONV FPDFPathSegment_GetType(FPDF_PATHSEGMENT segment); + +// Experimental API. +// Gets if the |segment| closes the current subpath of a given path. +// +// segment - handle to a segment. +// +// Returns close flag for non-NULL segment, FALSE otherwise. +FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV +FPDFPathSegment_GetClose(FPDF_PATHSEGMENT segment); + // Move a path's current point. // // path - the handle to the path object. diff --git a/public/fpdfview.h b/public/fpdfview.h index 135d00a8f4..3f180335d3 100644 --- a/public/fpdfview.h +++ b/public/fpdfview.h @@ -52,6 +52,7 @@ typedef void* FPDF_SCHHANDLE; typedef void* FPDF_STRUCTELEMENT; typedef void* FPDF_STRUCTTREE; typedef void* FPDF_TEXTPAGE; +typedef void const* FPDF_PATHSEGMENT; #ifdef PDF_ENABLE_XFA typedef void* FPDF_STRINGHANDLE; -- cgit v1.2.3