1*3ac0a46fSAndroid Build Coastguard Worker // Copyright 2017 The PDFium Authors
2*3ac0a46fSAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*3ac0a46fSAndroid Build Coastguard Worker // found in the LICENSE file.
4*3ac0a46fSAndroid Build Coastguard Worker
5*3ac0a46fSAndroid Build Coastguard Worker #include "public/fpdf_edit.h"
6*3ac0a46fSAndroid Build Coastguard Worker
7*3ac0a46fSAndroid Build Coastguard Worker #include <memory>
8*3ac0a46fSAndroid Build Coastguard Worker #include <utility>
9*3ac0a46fSAndroid Build Coastguard Worker
10*3ac0a46fSAndroid Build Coastguard Worker #include "core/fpdfapi/page/cpdf_path.h"
11*3ac0a46fSAndroid Build Coastguard Worker #include "core/fpdfapi/page/cpdf_pathobject.h"
12*3ac0a46fSAndroid Build Coastguard Worker #include "core/fxcrt/fx_system.h"
13*3ac0a46fSAndroid Build Coastguard Worker #include "core/fxcrt/stl_util.h"
14*3ac0a46fSAndroid Build Coastguard Worker #include "fpdfsdk/cpdfsdk_helpers.h"
15*3ac0a46fSAndroid Build Coastguard Worker #include "third_party/base/containers/span.h"
16*3ac0a46fSAndroid Build Coastguard Worker
17*3ac0a46fSAndroid Build Coastguard Worker // These checks are here because core/ and public/ cannot depend on each other.
18*3ac0a46fSAndroid Build Coastguard Worker static_assert(static_cast<int>(CFX_GraphStateData::LineCap::kButt) ==
19*3ac0a46fSAndroid Build Coastguard Worker FPDF_LINECAP_BUTT,
20*3ac0a46fSAndroid Build Coastguard Worker "CFX_GraphStateData::LineCap::kButt value mismatch");
21*3ac0a46fSAndroid Build Coastguard Worker static_assert(static_cast<int>(CFX_GraphStateData::LineCap::kRound) ==
22*3ac0a46fSAndroid Build Coastguard Worker FPDF_LINECAP_ROUND,
23*3ac0a46fSAndroid Build Coastguard Worker "CFX_GraphStateData::LineCap::kRound value mismatch");
24*3ac0a46fSAndroid Build Coastguard Worker static_assert(static_cast<int>(CFX_GraphStateData::LineCap::kSquare) ==
25*3ac0a46fSAndroid Build Coastguard Worker FPDF_LINECAP_PROJECTING_SQUARE,
26*3ac0a46fSAndroid Build Coastguard Worker "CFX_GraphStateData::LineCap::kSquare value mismatch");
27*3ac0a46fSAndroid Build Coastguard Worker
28*3ac0a46fSAndroid Build Coastguard Worker static_assert(static_cast<int>(CFX_GraphStateData::LineJoin::kMiter) ==
29*3ac0a46fSAndroid Build Coastguard Worker FPDF_LINEJOIN_MITER,
30*3ac0a46fSAndroid Build Coastguard Worker "CFX_GraphStateData::LineJoin::kMiter value mismatch");
31*3ac0a46fSAndroid Build Coastguard Worker static_assert(static_cast<int>(CFX_GraphStateData::LineJoin::kRound) ==
32*3ac0a46fSAndroid Build Coastguard Worker FPDF_LINEJOIN_ROUND,
33*3ac0a46fSAndroid Build Coastguard Worker "CFX_GraphStateData::LineJoin::kRound value mismatch");
34*3ac0a46fSAndroid Build Coastguard Worker static_assert(static_cast<int>(CFX_GraphStateData::LineJoin::kBevel) ==
35*3ac0a46fSAndroid Build Coastguard Worker FPDF_LINEJOIN_BEVEL,
36*3ac0a46fSAndroid Build Coastguard Worker "CFX_GraphStateData::LineJoin::kBevel value mismatch");
37*3ac0a46fSAndroid Build Coastguard Worker
38*3ac0a46fSAndroid Build Coastguard Worker static_assert(static_cast<int>(CFX_Path::Point::Type::kLine) ==
39*3ac0a46fSAndroid Build Coastguard Worker FPDF_SEGMENT_LINETO,
40*3ac0a46fSAndroid Build Coastguard Worker "CFX_Path::Point::Type::kLine value mismatch");
41*3ac0a46fSAndroid Build Coastguard Worker static_assert(static_cast<int>(CFX_Path::Point::Type::kBezier) ==
42*3ac0a46fSAndroid Build Coastguard Worker FPDF_SEGMENT_BEZIERTO,
43*3ac0a46fSAndroid Build Coastguard Worker "CFX_Path::Point::Type::kBezier value mismatch");
44*3ac0a46fSAndroid Build Coastguard Worker static_assert(static_cast<int>(CFX_Path::Point::Type::kMove) ==
45*3ac0a46fSAndroid Build Coastguard Worker FPDF_SEGMENT_MOVETO,
46*3ac0a46fSAndroid Build Coastguard Worker "CFX_Path::Point::Type::kMove value mismatch");
47*3ac0a46fSAndroid Build Coastguard Worker
48*3ac0a46fSAndroid Build Coastguard Worker namespace {
49*3ac0a46fSAndroid Build Coastguard Worker
CPDFPathObjectFromFPDFPageObject(FPDF_PAGEOBJECT page_object)50*3ac0a46fSAndroid Build Coastguard Worker CPDF_PathObject* CPDFPathObjectFromFPDFPageObject(FPDF_PAGEOBJECT page_object) {
51*3ac0a46fSAndroid Build Coastguard Worker auto* obj = CPDFPageObjectFromFPDFPageObject(page_object);
52*3ac0a46fSAndroid Build Coastguard Worker return obj ? obj->AsPath() : nullptr;
53*3ac0a46fSAndroid Build Coastguard Worker }
54*3ac0a46fSAndroid Build Coastguard Worker
55*3ac0a46fSAndroid Build Coastguard Worker } // namespace
56*3ac0a46fSAndroid Build Coastguard Worker
FPDFPageObj_CreateNewPath(float x,float y)57*3ac0a46fSAndroid Build Coastguard Worker FPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV FPDFPageObj_CreateNewPath(float x,
58*3ac0a46fSAndroid Build Coastguard Worker float y) {
59*3ac0a46fSAndroid Build Coastguard Worker auto pPathObj = std::make_unique<CPDF_PathObject>();
60*3ac0a46fSAndroid Build Coastguard Worker pPathObj->path().AppendPoint(CFX_PointF(x, y), CFX_Path::Point::Type::kMove);
61*3ac0a46fSAndroid Build Coastguard Worker pPathObj->DefaultStates();
62*3ac0a46fSAndroid Build Coastguard Worker
63*3ac0a46fSAndroid Build Coastguard Worker // Caller takes ownership.
64*3ac0a46fSAndroid Build Coastguard Worker return FPDFPageObjectFromCPDFPageObject(pPathObj.release());
65*3ac0a46fSAndroid Build Coastguard Worker }
66*3ac0a46fSAndroid Build Coastguard Worker
FPDFPageObj_CreateNewRect(float x,float y,float w,float h)67*3ac0a46fSAndroid Build Coastguard Worker FPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV FPDFPageObj_CreateNewRect(float x,
68*3ac0a46fSAndroid Build Coastguard Worker float y,
69*3ac0a46fSAndroid Build Coastguard Worker float w,
70*3ac0a46fSAndroid Build Coastguard Worker float h) {
71*3ac0a46fSAndroid Build Coastguard Worker auto pPathObj = std::make_unique<CPDF_PathObject>();
72*3ac0a46fSAndroid Build Coastguard Worker pPathObj->path().AppendRect(x, y, x + w, y + h);
73*3ac0a46fSAndroid Build Coastguard Worker pPathObj->DefaultStates();
74*3ac0a46fSAndroid Build Coastguard Worker
75*3ac0a46fSAndroid Build Coastguard Worker // Caller takes ownership.
76*3ac0a46fSAndroid Build Coastguard Worker return FPDFPageObjectFromCPDFPageObject(pPathObj.release());
77*3ac0a46fSAndroid Build Coastguard Worker }
78*3ac0a46fSAndroid Build Coastguard Worker
FPDFPath_CountSegments(FPDF_PAGEOBJECT path)79*3ac0a46fSAndroid Build Coastguard Worker FPDF_EXPORT int FPDF_CALLCONV FPDFPath_CountSegments(FPDF_PAGEOBJECT path) {
80*3ac0a46fSAndroid Build Coastguard Worker auto* pPathObj = CPDFPathObjectFromFPDFPageObject(path);
81*3ac0a46fSAndroid Build Coastguard Worker if (!pPathObj)
82*3ac0a46fSAndroid Build Coastguard Worker return -1;
83*3ac0a46fSAndroid Build Coastguard Worker return fxcrt::CollectionSize<int>(pPathObj->path().GetPoints());
84*3ac0a46fSAndroid Build Coastguard Worker }
85*3ac0a46fSAndroid Build Coastguard Worker
86*3ac0a46fSAndroid Build Coastguard Worker FPDF_EXPORT FPDF_PATHSEGMENT FPDF_CALLCONV
FPDFPath_GetPathSegment(FPDF_PAGEOBJECT path,int index)87*3ac0a46fSAndroid Build Coastguard Worker FPDFPath_GetPathSegment(FPDF_PAGEOBJECT path, int index) {
88*3ac0a46fSAndroid Build Coastguard Worker auto* pPathObj = CPDFPathObjectFromFPDFPageObject(path);
89*3ac0a46fSAndroid Build Coastguard Worker if (!pPathObj)
90*3ac0a46fSAndroid Build Coastguard Worker return nullptr;
91*3ac0a46fSAndroid Build Coastguard Worker
92*3ac0a46fSAndroid Build Coastguard Worker pdfium::span<const CFX_Path::Point> points = pPathObj->path().GetPoints();
93*3ac0a46fSAndroid Build Coastguard Worker if (!fxcrt::IndexInBounds(points, index))
94*3ac0a46fSAndroid Build Coastguard Worker return nullptr;
95*3ac0a46fSAndroid Build Coastguard Worker
96*3ac0a46fSAndroid Build Coastguard Worker return FPDFPathSegmentFromFXPathPoint(&points[index]);
97*3ac0a46fSAndroid Build Coastguard Worker }
98*3ac0a46fSAndroid Build Coastguard Worker
FPDFPath_MoveTo(FPDF_PAGEOBJECT path,float x,float y)99*3ac0a46fSAndroid Build Coastguard Worker FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPath_MoveTo(FPDF_PAGEOBJECT path,
100*3ac0a46fSAndroid Build Coastguard Worker float x,
101*3ac0a46fSAndroid Build Coastguard Worker float y) {
102*3ac0a46fSAndroid Build Coastguard Worker auto* pPathObj = CPDFPathObjectFromFPDFPageObject(path);
103*3ac0a46fSAndroid Build Coastguard Worker if (!pPathObj)
104*3ac0a46fSAndroid Build Coastguard Worker return false;
105*3ac0a46fSAndroid Build Coastguard Worker
106*3ac0a46fSAndroid Build Coastguard Worker pPathObj->path().AppendPoint(CFX_PointF(x, y), CFX_Path::Point::Type::kMove);
107*3ac0a46fSAndroid Build Coastguard Worker pPathObj->SetDirty(true);
108*3ac0a46fSAndroid Build Coastguard Worker return true;
109*3ac0a46fSAndroid Build Coastguard Worker }
110*3ac0a46fSAndroid Build Coastguard Worker
FPDFPath_LineTo(FPDF_PAGEOBJECT path,float x,float y)111*3ac0a46fSAndroid Build Coastguard Worker FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPath_LineTo(FPDF_PAGEOBJECT path,
112*3ac0a46fSAndroid Build Coastguard Worker float x,
113*3ac0a46fSAndroid Build Coastguard Worker float y) {
114*3ac0a46fSAndroid Build Coastguard Worker auto* pPathObj = CPDFPathObjectFromFPDFPageObject(path);
115*3ac0a46fSAndroid Build Coastguard Worker if (!pPathObj)
116*3ac0a46fSAndroid Build Coastguard Worker return false;
117*3ac0a46fSAndroid Build Coastguard Worker
118*3ac0a46fSAndroid Build Coastguard Worker pPathObj->path().AppendPoint(CFX_PointF(x, y), CFX_Path::Point::Type::kLine);
119*3ac0a46fSAndroid Build Coastguard Worker pPathObj->SetDirty(true);
120*3ac0a46fSAndroid Build Coastguard Worker return true;
121*3ac0a46fSAndroid Build Coastguard Worker }
122*3ac0a46fSAndroid Build Coastguard Worker
FPDFPath_BezierTo(FPDF_PAGEOBJECT path,float x1,float y1,float x2,float y2,float x3,float y3)123*3ac0a46fSAndroid Build Coastguard Worker FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPath_BezierTo(FPDF_PAGEOBJECT path,
124*3ac0a46fSAndroid Build Coastguard Worker float x1,
125*3ac0a46fSAndroid Build Coastguard Worker float y1,
126*3ac0a46fSAndroid Build Coastguard Worker float x2,
127*3ac0a46fSAndroid Build Coastguard Worker float y2,
128*3ac0a46fSAndroid Build Coastguard Worker float x3,
129*3ac0a46fSAndroid Build Coastguard Worker float y3) {
130*3ac0a46fSAndroid Build Coastguard Worker auto* pPathObj = CPDFPathObjectFromFPDFPageObject(path);
131*3ac0a46fSAndroid Build Coastguard Worker if (!pPathObj)
132*3ac0a46fSAndroid Build Coastguard Worker return false;
133*3ac0a46fSAndroid Build Coastguard Worker
134*3ac0a46fSAndroid Build Coastguard Worker CPDF_Path& cpath = pPathObj->path();
135*3ac0a46fSAndroid Build Coastguard Worker cpath.AppendPoint(CFX_PointF(x1, y1), CFX_Path::Point::Type::kBezier);
136*3ac0a46fSAndroid Build Coastguard Worker cpath.AppendPoint(CFX_PointF(x2, y2), CFX_Path::Point::Type::kBezier);
137*3ac0a46fSAndroid Build Coastguard Worker cpath.AppendPoint(CFX_PointF(x3, y3), CFX_Path::Point::Type::kBezier);
138*3ac0a46fSAndroid Build Coastguard Worker pPathObj->SetDirty(true);
139*3ac0a46fSAndroid Build Coastguard Worker return true;
140*3ac0a46fSAndroid Build Coastguard Worker }
141*3ac0a46fSAndroid Build Coastguard Worker
FPDFPath_Close(FPDF_PAGEOBJECT path)142*3ac0a46fSAndroid Build Coastguard Worker FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPath_Close(FPDF_PAGEOBJECT path) {
143*3ac0a46fSAndroid Build Coastguard Worker auto* pPathObj = CPDFPathObjectFromFPDFPageObject(path);
144*3ac0a46fSAndroid Build Coastguard Worker if (!pPathObj)
145*3ac0a46fSAndroid Build Coastguard Worker return false;
146*3ac0a46fSAndroid Build Coastguard Worker
147*3ac0a46fSAndroid Build Coastguard Worker CPDF_Path& cpath = pPathObj->path();
148*3ac0a46fSAndroid Build Coastguard Worker if (cpath.GetPoints().empty())
149*3ac0a46fSAndroid Build Coastguard Worker return false;
150*3ac0a46fSAndroid Build Coastguard Worker
151*3ac0a46fSAndroid Build Coastguard Worker cpath.ClosePath();
152*3ac0a46fSAndroid Build Coastguard Worker pPathObj->SetDirty(true);
153*3ac0a46fSAndroid Build Coastguard Worker return true;
154*3ac0a46fSAndroid Build Coastguard Worker }
155*3ac0a46fSAndroid Build Coastguard Worker
FPDFPath_SetDrawMode(FPDF_PAGEOBJECT path,int fillmode,FPDF_BOOL stroke)156*3ac0a46fSAndroid Build Coastguard Worker FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPath_SetDrawMode(FPDF_PAGEOBJECT path,
157*3ac0a46fSAndroid Build Coastguard Worker int fillmode,
158*3ac0a46fSAndroid Build Coastguard Worker FPDF_BOOL stroke) {
159*3ac0a46fSAndroid Build Coastguard Worker auto* pPathObj = CPDFPathObjectFromFPDFPageObject(path);
160*3ac0a46fSAndroid Build Coastguard Worker if (!pPathObj)
161*3ac0a46fSAndroid Build Coastguard Worker return false;
162*3ac0a46fSAndroid Build Coastguard Worker
163*3ac0a46fSAndroid Build Coastguard Worker pPathObj->set_stroke(!!stroke);
164*3ac0a46fSAndroid Build Coastguard Worker if (fillmode == FPDF_FILLMODE_ALTERNATE)
165*3ac0a46fSAndroid Build Coastguard Worker pPathObj->set_alternate_filltype();
166*3ac0a46fSAndroid Build Coastguard Worker else if (fillmode == FPDF_FILLMODE_WINDING)
167*3ac0a46fSAndroid Build Coastguard Worker pPathObj->set_winding_filltype();
168*3ac0a46fSAndroid Build Coastguard Worker else
169*3ac0a46fSAndroid Build Coastguard Worker pPathObj->set_no_filltype();
170*3ac0a46fSAndroid Build Coastguard Worker pPathObj->SetDirty(true);
171*3ac0a46fSAndroid Build Coastguard Worker return true;
172*3ac0a46fSAndroid Build Coastguard Worker }
173*3ac0a46fSAndroid Build Coastguard Worker
FPDFPath_GetDrawMode(FPDF_PAGEOBJECT path,int * fillmode,FPDF_BOOL * stroke)174*3ac0a46fSAndroid Build Coastguard Worker FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPath_GetDrawMode(FPDF_PAGEOBJECT path,
175*3ac0a46fSAndroid Build Coastguard Worker int* fillmode,
176*3ac0a46fSAndroid Build Coastguard Worker FPDF_BOOL* stroke) {
177*3ac0a46fSAndroid Build Coastguard Worker auto* pPathObj = CPDFPathObjectFromFPDFPageObject(path);
178*3ac0a46fSAndroid Build Coastguard Worker if (!pPathObj || !fillmode || !stroke)
179*3ac0a46fSAndroid Build Coastguard Worker return false;
180*3ac0a46fSAndroid Build Coastguard Worker
181*3ac0a46fSAndroid Build Coastguard Worker if (pPathObj->has_alternate_filltype())
182*3ac0a46fSAndroid Build Coastguard Worker *fillmode = FPDF_FILLMODE_ALTERNATE;
183*3ac0a46fSAndroid Build Coastguard Worker else if (pPathObj->has_winding_filltype())
184*3ac0a46fSAndroid Build Coastguard Worker *fillmode = FPDF_FILLMODE_WINDING;
185*3ac0a46fSAndroid Build Coastguard Worker else
186*3ac0a46fSAndroid Build Coastguard Worker *fillmode = FPDF_FILLMODE_NONE;
187*3ac0a46fSAndroid Build Coastguard Worker
188*3ac0a46fSAndroid Build Coastguard Worker *stroke = pPathObj->stroke();
189*3ac0a46fSAndroid Build Coastguard Worker return true;
190*3ac0a46fSAndroid Build Coastguard Worker }
191*3ac0a46fSAndroid Build Coastguard Worker
192*3ac0a46fSAndroid Build Coastguard Worker FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDFPathSegment_GetPoint(FPDF_PATHSEGMENT segment,float * x,float * y)193*3ac0a46fSAndroid Build Coastguard Worker FPDFPathSegment_GetPoint(FPDF_PATHSEGMENT segment, float* x, float* y) {
194*3ac0a46fSAndroid Build Coastguard Worker auto* pPathPoint = FXPathPointFromFPDFPathSegment(segment);
195*3ac0a46fSAndroid Build Coastguard Worker if (!pPathPoint || !x || !y)
196*3ac0a46fSAndroid Build Coastguard Worker return false;
197*3ac0a46fSAndroid Build Coastguard Worker
198*3ac0a46fSAndroid Build Coastguard Worker *x = pPathPoint->m_Point.x;
199*3ac0a46fSAndroid Build Coastguard Worker *y = pPathPoint->m_Point.y;
200*3ac0a46fSAndroid Build Coastguard Worker return true;
201*3ac0a46fSAndroid Build Coastguard Worker }
202*3ac0a46fSAndroid Build Coastguard Worker
203*3ac0a46fSAndroid Build Coastguard Worker FPDF_EXPORT int FPDF_CALLCONV
FPDFPathSegment_GetType(FPDF_PATHSEGMENT segment)204*3ac0a46fSAndroid Build Coastguard Worker FPDFPathSegment_GetType(FPDF_PATHSEGMENT segment) {
205*3ac0a46fSAndroid Build Coastguard Worker auto* pPathPoint = FXPathPointFromFPDFPathSegment(segment);
206*3ac0a46fSAndroid Build Coastguard Worker return pPathPoint ? static_cast<int>(pPathPoint->m_Type)
207*3ac0a46fSAndroid Build Coastguard Worker : FPDF_SEGMENT_UNKNOWN;
208*3ac0a46fSAndroid Build Coastguard Worker }
209*3ac0a46fSAndroid Build Coastguard Worker
210*3ac0a46fSAndroid Build Coastguard Worker FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDFPathSegment_GetClose(FPDF_PATHSEGMENT segment)211*3ac0a46fSAndroid Build Coastguard Worker FPDFPathSegment_GetClose(FPDF_PATHSEGMENT segment) {
212*3ac0a46fSAndroid Build Coastguard Worker auto* pPathPoint = FXPathPointFromFPDFPathSegment(segment);
213*3ac0a46fSAndroid Build Coastguard Worker return pPathPoint && pPathPoint->m_CloseFigure;
214*3ac0a46fSAndroid Build Coastguard Worker }
215