• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2017 PDFium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include <vector>
6 
7 #include "public/fpdf_edit.h"
8 
9 #include "core/fpdfapi/page/cpdf_path.h"
10 #include "core/fpdfapi/page/cpdf_pathobject.h"
11 #include "core/fxcrt/fx_system.h"
12 #include "fpdfsdk/fsdk_define.h"
13 #include "third_party/base/ptr_util.h"
14 
15 // These checks are here because core/ and public/ cannot depend on each other.
16 static_assert(CFX_GraphStateData::LineCapButt == FPDF_LINECAP_BUTT,
17               "CFX_GraphStateData::LineCapButt value mismatch");
18 static_assert(CFX_GraphStateData::LineCapRound == FPDF_LINECAP_ROUND,
19               "CFX_GraphStateData::LineCapRound value mismatch");
20 static_assert(CFX_GraphStateData::LineCapSquare ==
21                   FPDF_LINECAP_PROJECTING_SQUARE,
22               "CFX_GraphStateData::LineCapSquare value mismatch");
23 
24 static_assert(CFX_GraphStateData::LineJoinMiter == FPDF_LINEJOIN_MITER,
25               "CFX_GraphStateData::LineJoinMiter value mismatch");
26 static_assert(CFX_GraphStateData::LineJoinRound == FPDF_LINEJOIN_ROUND,
27               "CFX_GraphStateData::LineJoinRound value mismatch");
28 static_assert(CFX_GraphStateData::LineJoinBevel == FPDF_LINEJOIN_BEVEL,
29               "CFX_GraphStateData::LineJoinBevel value mismatch");
30 
31 static_assert(static_cast<int>(FXPT_TYPE::LineTo) == FPDF_SEGMENT_LINETO,
32               "FXPT_TYPE::LineTo value mismatch");
33 static_assert(static_cast<int>(FXPT_TYPE::BezierTo) == FPDF_SEGMENT_BEZIERTO,
34               "FXPT_TYPE::BezierTo value mismatch");
35 static_assert(static_cast<int>(FXPT_TYPE::MoveTo) == FPDF_SEGMENT_MOVETO,
36               "FXPT_TYPE::MoveTo value mismatch");
37 
FPDFPageObj_CreateNewPath(float x,float y)38 FPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV FPDFPageObj_CreateNewPath(float x,
39                                                                     float y) {
40   auto pPathObj = pdfium::MakeUnique<CPDF_PathObject>();
41   pPathObj->m_Path.AppendPoint(CFX_PointF(x, y), FXPT_TYPE::MoveTo, false);
42   pPathObj->DefaultStates();
43   return pPathObj.release();  // Caller takes ownership.
44 }
45 
FPDFPageObj_CreateNewRect(float x,float y,float w,float h)46 FPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV FPDFPageObj_CreateNewRect(float x,
47                                                                     float y,
48                                                                     float w,
49                                                                     float h) {
50   auto pPathObj = pdfium::MakeUnique<CPDF_PathObject>();
51   pPathObj->m_Path.AppendRect(x, y, x + w, y + h);
52   pPathObj->DefaultStates();
53   return pPathObj.release();  // Caller takes ownership.
54 }
55 
56 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDFPath_SetStrokeColor(FPDF_PAGEOBJECT path,unsigned int R,unsigned int G,unsigned int B,unsigned int A)57 FPDFPath_SetStrokeColor(FPDF_PAGEOBJECT path,
58                         unsigned int R,
59                         unsigned int G,
60                         unsigned int B,
61                         unsigned int A) {
62   auto* pPathObj = CPDFPathObjectFromFPDFPageObject(path);
63   if (!pPathObj || R > 255 || G > 255 || B > 255 || A > 255)
64     return false;
65 
66   float rgb[3] = {R / 255.f, G / 255.f, B / 255.f};
67   pPathObj->m_GeneralState.SetStrokeAlpha(A / 255.f);
68   pPathObj->m_ColorState.SetStrokeColor(
69       CPDF_ColorSpace::GetStockCS(PDFCS_DEVICERGB), rgb, 3);
70   pPathObj->SetDirty(true);
71   return true;
72 }
73 
74 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDFPath_GetStrokeColor(FPDF_PAGEOBJECT path,unsigned int * R,unsigned int * G,unsigned int * B,unsigned int * A)75 FPDFPath_GetStrokeColor(FPDF_PAGEOBJECT path,
76                         unsigned int* R,
77                         unsigned int* G,
78                         unsigned int* B,
79                         unsigned int* A) {
80   auto* pPathObj = CPDFPathObjectFromFPDFPageObject(path);
81   if (!pPathObj || !R || !G || !B || !A)
82     return false;
83 
84   uint32_t strokeRGB = pPathObj->m_ColorState.GetStrokeRGB();
85   *R = FXSYS_GetRValue(strokeRGB);
86   *G = FXSYS_GetGValue(strokeRGB);
87   *B = FXSYS_GetBValue(strokeRGB);
88   *A = static_cast<unsigned int>(
89       (pPathObj->m_GeneralState.GetStrokeAlpha() * 255.f) + 0.5f);
90   return true;
91 }
92 
93 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDFPath_SetStrokeWidth(FPDF_PAGEOBJECT path,float width)94 FPDFPath_SetStrokeWidth(FPDF_PAGEOBJECT path, float width) {
95   auto* pPathObj = CPDFPathObjectFromFPDFPageObject(path);
96   if (!pPathObj || width < 0.0f)
97     return false;
98 
99   pPathObj->m_GraphState.SetLineWidth(width);
100   pPathObj->SetDirty(true);
101   return true;
102 }
103 
FPDFPath_SetFillColor(FPDF_PAGEOBJECT path,unsigned int R,unsigned int G,unsigned int B,unsigned int A)104 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPath_SetFillColor(FPDF_PAGEOBJECT path,
105                                                           unsigned int R,
106                                                           unsigned int G,
107                                                           unsigned int B,
108                                                           unsigned int A) {
109   return FPDFPageObj_SetFillColor(path, R, G, B, A);
110 }
111 
FPDFPath_GetFillColor(FPDF_PAGEOBJECT path,unsigned int * R,unsigned int * G,unsigned int * B,unsigned int * A)112 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPath_GetFillColor(FPDF_PAGEOBJECT path,
113                                                           unsigned int* R,
114                                                           unsigned int* G,
115                                                           unsigned int* B,
116                                                           unsigned int* A) {
117   auto* pPathObj = CPDFPathObjectFromFPDFPageObject(path);
118   if (!pPathObj || !R || !G || !B || !A)
119     return false;
120 
121   uint32_t fillRGB = pPathObj->m_ColorState.GetFillRGB();
122   *R = FXSYS_GetRValue(fillRGB);
123   *G = FXSYS_GetGValue(fillRGB);
124   *B = FXSYS_GetBValue(fillRGB);
125   *A = static_cast<unsigned int>(
126       (pPathObj->m_GeneralState.GetFillAlpha() * 255.f) + 0.5f);
127   return true;
128 }
129 
FPDFPath_CountSegments(FPDF_PAGEOBJECT path)130 FPDF_EXPORT int FPDF_CALLCONV FPDFPath_CountSegments(FPDF_PAGEOBJECT path) {
131   auto* pPathObj = CPDFPathObjectFromFPDFPageObject(path);
132   if (!pPathObj)
133     return -1;
134   return pdfium::CollectionSize<int>(pPathObj->m_Path.GetPoints());
135 }
136 
137 FPDF_EXPORT FPDF_PATHSEGMENT FPDF_CALLCONV
FPDFPath_GetPathSegment(FPDF_PAGEOBJECT path,int index)138 FPDFPath_GetPathSegment(FPDF_PAGEOBJECT path, int index) {
139   auto* pPathObj = CPDFPathObjectFromFPDFPageObject(path);
140   if (!pPathObj)
141     return nullptr;
142 
143   const std::vector<FX_PATHPOINT>& points = pPathObj->m_Path.GetPoints();
144   return pdfium::IndexInBounds(points, index) ? &points[index] : nullptr;
145 }
146 
FPDFPath_MoveTo(FPDF_PAGEOBJECT path,float x,float y)147 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPath_MoveTo(FPDF_PAGEOBJECT path,
148                                                     float x,
149                                                     float y) {
150   auto* pPathObj = CPDFPathObjectFromFPDFPageObject(path);
151   if (!pPathObj)
152     return false;
153 
154   pPathObj->m_Path.AppendPoint(CFX_PointF(x, y), FXPT_TYPE::MoveTo, false);
155   pPathObj->SetDirty(true);
156   return true;
157 }
158 
FPDFPath_LineTo(FPDF_PAGEOBJECT path,float x,float y)159 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPath_LineTo(FPDF_PAGEOBJECT path,
160                                                     float x,
161                                                     float y) {
162   auto* pPathObj = CPDFPathObjectFromFPDFPageObject(path);
163   if (!pPathObj)
164     return false;
165 
166   pPathObj->m_Path.AppendPoint(CFX_PointF(x, y), FXPT_TYPE::LineTo, false);
167   pPathObj->SetDirty(true);
168   return true;
169 }
170 
FPDFPath_BezierTo(FPDF_PAGEOBJECT path,float x1,float y1,float x2,float y2,float x3,float y3)171 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPath_BezierTo(FPDF_PAGEOBJECT path,
172                                                       float x1,
173                                                       float y1,
174                                                       float x2,
175                                                       float y2,
176                                                       float x3,
177                                                       float y3) {
178   auto* pPathObj = CPDFPathObjectFromFPDFPageObject(path);
179   if (!pPathObj)
180     return false;
181 
182   pPathObj->m_Path.AppendPoint(CFX_PointF(x1, y1), FXPT_TYPE::BezierTo, false);
183   pPathObj->m_Path.AppendPoint(CFX_PointF(x2, y2), FXPT_TYPE::BezierTo, false);
184   pPathObj->m_Path.AppendPoint(CFX_PointF(x3, y3), FXPT_TYPE::BezierTo, false);
185   pPathObj->SetDirty(true);
186   return true;
187 }
188 
FPDFPath_Close(FPDF_PAGEOBJECT path)189 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPath_Close(FPDF_PAGEOBJECT path) {
190   auto* pPathObj = CPDFPathObjectFromFPDFPageObject(path);
191   if (!pPathObj)
192     return false;
193 
194   if (pPathObj->m_Path.GetPoints().empty())
195     return false;
196 
197   pPathObj->m_Path.ClosePath();
198   pPathObj->SetDirty(true);
199   return true;
200 }
201 
FPDFPath_SetDrawMode(FPDF_PAGEOBJECT path,int fillmode,FPDF_BOOL stroke)202 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPath_SetDrawMode(FPDF_PAGEOBJECT path,
203                                                          int fillmode,
204                                                          FPDF_BOOL stroke) {
205   auto* pPathObj = CPDFPathObjectFromFPDFPageObject(path);
206   if (!pPathObj)
207     return false;
208 
209   if (fillmode == FPDF_FILLMODE_ALTERNATE)
210     pPathObj->m_FillType = FXFILL_ALTERNATE;
211   else if (fillmode == FPDF_FILLMODE_WINDING)
212     pPathObj->m_FillType = FXFILL_WINDING;
213   else
214     pPathObj->m_FillType = 0;
215   pPathObj->m_bStroke = stroke != 0;
216   pPathObj->SetDirty(true);
217   return true;
218 }
219 
FPDFPath_SetLineJoin(FPDF_PAGEOBJECT path,int line_join)220 FPDF_EXPORT void FPDF_CALLCONV FPDFPath_SetLineJoin(FPDF_PAGEOBJECT path,
221                                                     int line_join) {
222   if (!path)
223     return;
224   if (line_join <
225           static_cast<int>(CFX_GraphStateData::LineJoin::LineJoinMiter) ||
226       line_join >
227           static_cast<int>(CFX_GraphStateData::LineJoin::LineJoinBevel)) {
228     return;
229   }
230   auto* pPathObj = CPDFPageObjectFromFPDFPageObject(path);
231   CFX_GraphStateData::LineJoin lineJoin =
232       static_cast<CFX_GraphStateData::LineJoin>(line_join);
233   pPathObj->m_GraphState.SetLineJoin(lineJoin);
234   pPathObj->SetDirty(true);
235 }
236 
FPDFPath_SetLineCap(FPDF_PAGEOBJECT path,int line_cap)237 FPDF_EXPORT void FPDF_CALLCONV FPDFPath_SetLineCap(FPDF_PAGEOBJECT path,
238                                                    int line_cap) {
239   if (!path)
240     return;
241   if (line_cap < static_cast<int>(CFX_GraphStateData::LineCap::LineCapButt) ||
242       line_cap > static_cast<int>(CFX_GraphStateData::LineCap::LineCapSquare)) {
243     return;
244   }
245   auto* pPathObj = CPDFPageObjectFromFPDFPageObject(path);
246   CFX_GraphStateData::LineCap lineCap =
247       static_cast<CFX_GraphStateData::LineCap>(line_cap);
248   pPathObj->m_GraphState.SetLineCap(lineCap);
249   pPathObj->SetDirty(true);
250 }
251 
252 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDFPathSegment_GetPoint(FPDF_PATHSEGMENT segment,float * x,float * y)253 FPDFPathSegment_GetPoint(FPDF_PATHSEGMENT segment, float* x, float* y) {
254   auto* pPathPoint = FXPathPointFromFPDFPathSegment(segment);
255   if (!pPathPoint || !x || !y)
256     return false;
257 
258   *x = pPathPoint->m_Point.x;
259   *y = pPathPoint->m_Point.y;
260 
261   return true;
262 }
263 
264 FPDF_EXPORT int FPDF_CALLCONV
FPDFPathSegment_GetType(FPDF_PATHSEGMENT segment)265 FPDFPathSegment_GetType(FPDF_PATHSEGMENT segment) {
266   auto* pPathPoint = FXPathPointFromFPDFPathSegment(segment);
267 
268   return pPathPoint ? static_cast<int>(pPathPoint->m_Type)
269                     : FPDF_SEGMENT_UNKNOWN;
270 }
271 
272 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDFPathSegment_GetClose(FPDF_PATHSEGMENT segment)273 FPDFPathSegment_GetClose(FPDF_PATHSEGMENT segment) {
274   auto* pPathPoint = FXPathPointFromFPDFPathSegment(segment);
275 
276   return pPathPoint ? pPathPoint->m_CloseFigure : false;
277 }
278