xref: /aosp_15_r20/external/pdfium/fpdfsdk/fpdf_transformpage.cpp (revision 3ac0a46f773bac49fa9476ec2b1cf3f8da5ec3a4)
1*3ac0a46fSAndroid Build Coastguard Worker // Copyright 2014 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 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6*3ac0a46fSAndroid Build Coastguard Worker 
7*3ac0a46fSAndroid Build Coastguard Worker #include "public/fpdf_transformpage.h"
8*3ac0a46fSAndroid Build Coastguard Worker 
9*3ac0a46fSAndroid Build Coastguard Worker #include <memory>
10*3ac0a46fSAndroid Build Coastguard Worker #include <sstream>
11*3ac0a46fSAndroid Build Coastguard Worker 
12*3ac0a46fSAndroid Build Coastguard Worker #include "constants/page_object.h"
13*3ac0a46fSAndroid Build Coastguard Worker #include "core/fpdfapi/edit/cpdf_contentstream_write_utils.h"
14*3ac0a46fSAndroid Build Coastguard Worker #include "core/fpdfapi/page/cpdf_clippath.h"
15*3ac0a46fSAndroid Build Coastguard Worker #include "core/fpdfapi/page/cpdf_page.h"
16*3ac0a46fSAndroid Build Coastguard Worker #include "core/fpdfapi/page/cpdf_pageobject.h"
17*3ac0a46fSAndroid Build Coastguard Worker #include "core/fpdfapi/page/cpdf_path.h"
18*3ac0a46fSAndroid Build Coastguard Worker #include "core/fpdfapi/parser/cpdf_array.h"
19*3ac0a46fSAndroid Build Coastguard Worker #include "core/fpdfapi/parser/cpdf_dictionary.h"
20*3ac0a46fSAndroid Build Coastguard Worker #include "core/fpdfapi/parser/cpdf_document.h"
21*3ac0a46fSAndroid Build Coastguard Worker #include "core/fpdfapi/parser/cpdf_number.h"
22*3ac0a46fSAndroid Build Coastguard Worker #include "core/fpdfapi/parser/cpdf_reference.h"
23*3ac0a46fSAndroid Build Coastguard Worker #include "core/fpdfapi/parser/cpdf_stream.h"
24*3ac0a46fSAndroid Build Coastguard Worker #include "core/fxcrt/fx_string_wrappers.h"
25*3ac0a46fSAndroid Build Coastguard Worker #include "core/fxcrt/stl_util.h"
26*3ac0a46fSAndroid Build Coastguard Worker #include "core/fxge/cfx_fillrenderoptions.h"
27*3ac0a46fSAndroid Build Coastguard Worker #include "core/fxge/cfx_path.h"
28*3ac0a46fSAndroid Build Coastguard Worker #include "fpdfsdk/cpdfsdk_helpers.h"
29*3ac0a46fSAndroid Build Coastguard Worker #include "third_party/base/containers/span.h"
30*3ac0a46fSAndroid Build Coastguard Worker #include "third_party/base/numerics/safe_conversions.h"
31*3ac0a46fSAndroid Build Coastguard Worker 
32*3ac0a46fSAndroid Build Coastguard Worker namespace {
33*3ac0a46fSAndroid Build Coastguard Worker 
SetBoundingBox(CPDF_Page * page,const ByteString & key,const CFX_FloatRect & rect)34*3ac0a46fSAndroid Build Coastguard Worker void SetBoundingBox(CPDF_Page* page,
35*3ac0a46fSAndroid Build Coastguard Worker                     const ByteString& key,
36*3ac0a46fSAndroid Build Coastguard Worker                     const CFX_FloatRect& rect) {
37*3ac0a46fSAndroid Build Coastguard Worker   if (!page)
38*3ac0a46fSAndroid Build Coastguard Worker     return;
39*3ac0a46fSAndroid Build Coastguard Worker 
40*3ac0a46fSAndroid Build Coastguard Worker   page->GetMutableDict()->SetRectFor(key, rect);
41*3ac0a46fSAndroid Build Coastguard Worker   page->UpdateDimensions();
42*3ac0a46fSAndroid Build Coastguard Worker }
43*3ac0a46fSAndroid Build Coastguard Worker 
GetBoundingBox(const CPDF_Page * page,const ByteString & key,float * left,float * bottom,float * right,float * top)44*3ac0a46fSAndroid Build Coastguard Worker bool GetBoundingBox(const CPDF_Page* page,
45*3ac0a46fSAndroid Build Coastguard Worker                     const ByteString& key,
46*3ac0a46fSAndroid Build Coastguard Worker                     float* left,
47*3ac0a46fSAndroid Build Coastguard Worker                     float* bottom,
48*3ac0a46fSAndroid Build Coastguard Worker                     float* right,
49*3ac0a46fSAndroid Build Coastguard Worker                     float* top) {
50*3ac0a46fSAndroid Build Coastguard Worker   if (!page || !left || !bottom || !right || !top)
51*3ac0a46fSAndroid Build Coastguard Worker     return false;
52*3ac0a46fSAndroid Build Coastguard Worker 
53*3ac0a46fSAndroid Build Coastguard Worker   RetainPtr<const CPDF_Array> pArray = page->GetDict()->GetArrayFor(key);
54*3ac0a46fSAndroid Build Coastguard Worker   if (!pArray)
55*3ac0a46fSAndroid Build Coastguard Worker     return false;
56*3ac0a46fSAndroid Build Coastguard Worker 
57*3ac0a46fSAndroid Build Coastguard Worker   *left = pArray->GetFloatAt(0);
58*3ac0a46fSAndroid Build Coastguard Worker   *bottom = pArray->GetFloatAt(1);
59*3ac0a46fSAndroid Build Coastguard Worker   *right = pArray->GetFloatAt(2);
60*3ac0a46fSAndroid Build Coastguard Worker   *top = pArray->GetFloatAt(3);
61*3ac0a46fSAndroid Build Coastguard Worker   return true;
62*3ac0a46fSAndroid Build Coastguard Worker }
63*3ac0a46fSAndroid Build Coastguard Worker 
GetPageContent(CPDF_Dictionary * pPageDict)64*3ac0a46fSAndroid Build Coastguard Worker RetainPtr<CPDF_Object> GetPageContent(CPDF_Dictionary* pPageDict) {
65*3ac0a46fSAndroid Build Coastguard Worker   return pPageDict->GetMutableDirectObjectFor(pdfium::page_object::kContents);
66*3ac0a46fSAndroid Build Coastguard Worker }
67*3ac0a46fSAndroid Build Coastguard Worker 
OutputPath(fxcrt::ostringstream & buf,CPDF_Path path)68*3ac0a46fSAndroid Build Coastguard Worker void OutputPath(fxcrt::ostringstream& buf, CPDF_Path path) {
69*3ac0a46fSAndroid Build Coastguard Worker   const CFX_Path* pPath = path.GetObject();
70*3ac0a46fSAndroid Build Coastguard Worker   if (!pPath)
71*3ac0a46fSAndroid Build Coastguard Worker     return;
72*3ac0a46fSAndroid Build Coastguard Worker 
73*3ac0a46fSAndroid Build Coastguard Worker   pdfium::span<const CFX_Path::Point> points = pPath->GetPoints();
74*3ac0a46fSAndroid Build Coastguard Worker   if (path.IsRect()) {
75*3ac0a46fSAndroid Build Coastguard Worker     CFX_PointF diff = points[2].m_Point - points[0].m_Point;
76*3ac0a46fSAndroid Build Coastguard Worker     buf << points[0].m_Point.x << " " << points[0].m_Point.y << " " << diff.x
77*3ac0a46fSAndroid Build Coastguard Worker         << " " << diff.y << " re\n";
78*3ac0a46fSAndroid Build Coastguard Worker     return;
79*3ac0a46fSAndroid Build Coastguard Worker   }
80*3ac0a46fSAndroid Build Coastguard Worker 
81*3ac0a46fSAndroid Build Coastguard Worker   for (size_t i = 0; i < points.size(); ++i) {
82*3ac0a46fSAndroid Build Coastguard Worker     buf << points[i].m_Point.x << " " << points[i].m_Point.y;
83*3ac0a46fSAndroid Build Coastguard Worker     CFX_Path::Point::Type point_type = points[i].m_Type;
84*3ac0a46fSAndroid Build Coastguard Worker     if (point_type == CFX_Path::Point::Type::kMove) {
85*3ac0a46fSAndroid Build Coastguard Worker       buf << " m\n";
86*3ac0a46fSAndroid Build Coastguard Worker     } else if (point_type == CFX_Path::Point::Type::kBezier) {
87*3ac0a46fSAndroid Build Coastguard Worker       buf << " " << points[i + 1].m_Point.x << " " << points[i + 1].m_Point.y
88*3ac0a46fSAndroid Build Coastguard Worker           << " " << points[i + 2].m_Point.x << " " << points[i + 2].m_Point.y;
89*3ac0a46fSAndroid Build Coastguard Worker       buf << " c";
90*3ac0a46fSAndroid Build Coastguard Worker       if (points[i + 2].m_CloseFigure)
91*3ac0a46fSAndroid Build Coastguard Worker         buf << " h";
92*3ac0a46fSAndroid Build Coastguard Worker       buf << "\n";
93*3ac0a46fSAndroid Build Coastguard Worker 
94*3ac0a46fSAndroid Build Coastguard Worker       i += 2;
95*3ac0a46fSAndroid Build Coastguard Worker     } else if (point_type == CFX_Path::Point::Type::kLine) {
96*3ac0a46fSAndroid Build Coastguard Worker       buf << " l";
97*3ac0a46fSAndroid Build Coastguard Worker       if (points[i].m_CloseFigure)
98*3ac0a46fSAndroid Build Coastguard Worker         buf << " h";
99*3ac0a46fSAndroid Build Coastguard Worker       buf << "\n";
100*3ac0a46fSAndroid Build Coastguard Worker     }
101*3ac0a46fSAndroid Build Coastguard Worker   }
102*3ac0a46fSAndroid Build Coastguard Worker }
103*3ac0a46fSAndroid Build Coastguard Worker 
104*3ac0a46fSAndroid Build Coastguard Worker }  // namespace
105*3ac0a46fSAndroid Build Coastguard Worker 
FPDFPage_SetMediaBox(FPDF_PAGE page,float left,float bottom,float right,float top)106*3ac0a46fSAndroid Build Coastguard Worker FPDF_EXPORT void FPDF_CALLCONV FPDFPage_SetMediaBox(FPDF_PAGE page,
107*3ac0a46fSAndroid Build Coastguard Worker                                                     float left,
108*3ac0a46fSAndroid Build Coastguard Worker                                                     float bottom,
109*3ac0a46fSAndroid Build Coastguard Worker                                                     float right,
110*3ac0a46fSAndroid Build Coastguard Worker                                                     float top) {
111*3ac0a46fSAndroid Build Coastguard Worker   SetBoundingBox(CPDFPageFromFPDFPage(page), pdfium::page_object::kMediaBox,
112*3ac0a46fSAndroid Build Coastguard Worker                  CFX_FloatRect(left, bottom, right, top));
113*3ac0a46fSAndroid Build Coastguard Worker }
114*3ac0a46fSAndroid Build Coastguard Worker 
FPDFPage_SetCropBox(FPDF_PAGE page,float left,float bottom,float right,float top)115*3ac0a46fSAndroid Build Coastguard Worker FPDF_EXPORT void FPDF_CALLCONV FPDFPage_SetCropBox(FPDF_PAGE page,
116*3ac0a46fSAndroid Build Coastguard Worker                                                    float left,
117*3ac0a46fSAndroid Build Coastguard Worker                                                    float bottom,
118*3ac0a46fSAndroid Build Coastguard Worker                                                    float right,
119*3ac0a46fSAndroid Build Coastguard Worker                                                    float top) {
120*3ac0a46fSAndroid Build Coastguard Worker   SetBoundingBox(CPDFPageFromFPDFPage(page), pdfium::page_object::kCropBox,
121*3ac0a46fSAndroid Build Coastguard Worker                  CFX_FloatRect(left, bottom, right, top));
122*3ac0a46fSAndroid Build Coastguard Worker }
123*3ac0a46fSAndroid Build Coastguard Worker 
FPDFPage_SetBleedBox(FPDF_PAGE page,float left,float bottom,float right,float top)124*3ac0a46fSAndroid Build Coastguard Worker FPDF_EXPORT void FPDF_CALLCONV FPDFPage_SetBleedBox(FPDF_PAGE page,
125*3ac0a46fSAndroid Build Coastguard Worker                                                     float left,
126*3ac0a46fSAndroid Build Coastguard Worker                                                     float bottom,
127*3ac0a46fSAndroid Build Coastguard Worker                                                     float right,
128*3ac0a46fSAndroid Build Coastguard Worker                                                     float top) {
129*3ac0a46fSAndroid Build Coastguard Worker   SetBoundingBox(CPDFPageFromFPDFPage(page), pdfium::page_object::kBleedBox,
130*3ac0a46fSAndroid Build Coastguard Worker                  CFX_FloatRect(left, bottom, right, top));
131*3ac0a46fSAndroid Build Coastguard Worker }
132*3ac0a46fSAndroid Build Coastguard Worker 
FPDFPage_SetTrimBox(FPDF_PAGE page,float left,float bottom,float right,float top)133*3ac0a46fSAndroid Build Coastguard Worker FPDF_EXPORT void FPDF_CALLCONV FPDFPage_SetTrimBox(FPDF_PAGE page,
134*3ac0a46fSAndroid Build Coastguard Worker                                                    float left,
135*3ac0a46fSAndroid Build Coastguard Worker                                                    float bottom,
136*3ac0a46fSAndroid Build Coastguard Worker                                                    float right,
137*3ac0a46fSAndroid Build Coastguard Worker                                                    float top) {
138*3ac0a46fSAndroid Build Coastguard Worker   SetBoundingBox(CPDFPageFromFPDFPage(page), pdfium::page_object::kTrimBox,
139*3ac0a46fSAndroid Build Coastguard Worker                  CFX_FloatRect(left, bottom, right, top));
140*3ac0a46fSAndroid Build Coastguard Worker }
141*3ac0a46fSAndroid Build Coastguard Worker 
FPDFPage_SetArtBox(FPDF_PAGE page,float left,float bottom,float right,float top)142*3ac0a46fSAndroid Build Coastguard Worker FPDF_EXPORT void FPDF_CALLCONV FPDFPage_SetArtBox(FPDF_PAGE page,
143*3ac0a46fSAndroid Build Coastguard Worker                                                   float left,
144*3ac0a46fSAndroid Build Coastguard Worker                                                   float bottom,
145*3ac0a46fSAndroid Build Coastguard Worker                                                   float right,
146*3ac0a46fSAndroid Build Coastguard Worker                                                   float top) {
147*3ac0a46fSAndroid Build Coastguard Worker   SetBoundingBox(CPDFPageFromFPDFPage(page), pdfium::page_object::kArtBox,
148*3ac0a46fSAndroid Build Coastguard Worker                  CFX_FloatRect(left, bottom, right, top));
149*3ac0a46fSAndroid Build Coastguard Worker }
150*3ac0a46fSAndroid Build Coastguard Worker 
FPDFPage_GetMediaBox(FPDF_PAGE page,float * left,float * bottom,float * right,float * top)151*3ac0a46fSAndroid Build Coastguard Worker FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_GetMediaBox(FPDF_PAGE page,
152*3ac0a46fSAndroid Build Coastguard Worker                                                          float* left,
153*3ac0a46fSAndroid Build Coastguard Worker                                                          float* bottom,
154*3ac0a46fSAndroid Build Coastguard Worker                                                          float* right,
155*3ac0a46fSAndroid Build Coastguard Worker                                                          float* top) {
156*3ac0a46fSAndroid Build Coastguard Worker   return GetBoundingBox(CPDFPageFromFPDFPage(page),
157*3ac0a46fSAndroid Build Coastguard Worker                         pdfium::page_object::kMediaBox, left, bottom, right,
158*3ac0a46fSAndroid Build Coastguard Worker                         top);
159*3ac0a46fSAndroid Build Coastguard Worker }
160*3ac0a46fSAndroid Build Coastguard Worker 
FPDFPage_GetCropBox(FPDF_PAGE page,float * left,float * bottom,float * right,float * top)161*3ac0a46fSAndroid Build Coastguard Worker FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_GetCropBox(FPDF_PAGE page,
162*3ac0a46fSAndroid Build Coastguard Worker                                                         float* left,
163*3ac0a46fSAndroid Build Coastguard Worker                                                         float* bottom,
164*3ac0a46fSAndroid Build Coastguard Worker                                                         float* right,
165*3ac0a46fSAndroid Build Coastguard Worker                                                         float* top) {
166*3ac0a46fSAndroid Build Coastguard Worker   return GetBoundingBox(CPDFPageFromFPDFPage(page),
167*3ac0a46fSAndroid Build Coastguard Worker                         pdfium::page_object::kCropBox, left, bottom, right,
168*3ac0a46fSAndroid Build Coastguard Worker                         top);
169*3ac0a46fSAndroid Build Coastguard Worker }
170*3ac0a46fSAndroid Build Coastguard Worker 
FPDFPage_GetBleedBox(FPDF_PAGE page,float * left,float * bottom,float * right,float * top)171*3ac0a46fSAndroid Build Coastguard Worker FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_GetBleedBox(FPDF_PAGE page,
172*3ac0a46fSAndroid Build Coastguard Worker                                                          float* left,
173*3ac0a46fSAndroid Build Coastguard Worker                                                          float* bottom,
174*3ac0a46fSAndroid Build Coastguard Worker                                                          float* right,
175*3ac0a46fSAndroid Build Coastguard Worker                                                          float* top) {
176*3ac0a46fSAndroid Build Coastguard Worker   return GetBoundingBox(CPDFPageFromFPDFPage(page),
177*3ac0a46fSAndroid Build Coastguard Worker                         pdfium::page_object::kBleedBox, left, bottom, right,
178*3ac0a46fSAndroid Build Coastguard Worker                         top);
179*3ac0a46fSAndroid Build Coastguard Worker }
180*3ac0a46fSAndroid Build Coastguard Worker 
FPDFPage_GetTrimBox(FPDF_PAGE page,float * left,float * bottom,float * right,float * top)181*3ac0a46fSAndroid Build Coastguard Worker FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_GetTrimBox(FPDF_PAGE page,
182*3ac0a46fSAndroid Build Coastguard Worker                                                         float* left,
183*3ac0a46fSAndroid Build Coastguard Worker                                                         float* bottom,
184*3ac0a46fSAndroid Build Coastguard Worker                                                         float* right,
185*3ac0a46fSAndroid Build Coastguard Worker                                                         float* top) {
186*3ac0a46fSAndroid Build Coastguard Worker   return GetBoundingBox(CPDFPageFromFPDFPage(page),
187*3ac0a46fSAndroid Build Coastguard Worker                         pdfium::page_object::kTrimBox, left, bottom, right,
188*3ac0a46fSAndroid Build Coastguard Worker                         top);
189*3ac0a46fSAndroid Build Coastguard Worker }
190*3ac0a46fSAndroid Build Coastguard Worker 
FPDFPage_GetArtBox(FPDF_PAGE page,float * left,float * bottom,float * right,float * top)191*3ac0a46fSAndroid Build Coastguard Worker FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_GetArtBox(FPDF_PAGE page,
192*3ac0a46fSAndroid Build Coastguard Worker                                                        float* left,
193*3ac0a46fSAndroid Build Coastguard Worker                                                        float* bottom,
194*3ac0a46fSAndroid Build Coastguard Worker                                                        float* right,
195*3ac0a46fSAndroid Build Coastguard Worker                                                        float* top) {
196*3ac0a46fSAndroid Build Coastguard Worker   return GetBoundingBox(CPDFPageFromFPDFPage(page),
197*3ac0a46fSAndroid Build Coastguard Worker                         pdfium::page_object::kArtBox, left, bottom, right, top);
198*3ac0a46fSAndroid Build Coastguard Worker }
199*3ac0a46fSAndroid Build Coastguard Worker 
200*3ac0a46fSAndroid Build Coastguard Worker FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDFPage_TransFormWithClip(FPDF_PAGE page,const FS_MATRIX * matrix,const FS_RECTF * clipRect)201*3ac0a46fSAndroid Build Coastguard Worker FPDFPage_TransFormWithClip(FPDF_PAGE page,
202*3ac0a46fSAndroid Build Coastguard Worker                            const FS_MATRIX* matrix,
203*3ac0a46fSAndroid Build Coastguard Worker                            const FS_RECTF* clipRect) {
204*3ac0a46fSAndroid Build Coastguard Worker   if (!matrix && !clipRect)
205*3ac0a46fSAndroid Build Coastguard Worker     return false;
206*3ac0a46fSAndroid Build Coastguard Worker 
207*3ac0a46fSAndroid Build Coastguard Worker   CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
208*3ac0a46fSAndroid Build Coastguard Worker   if (!pPage)
209*3ac0a46fSAndroid Build Coastguard Worker     return false;
210*3ac0a46fSAndroid Build Coastguard Worker 
211*3ac0a46fSAndroid Build Coastguard Worker   RetainPtr<CPDF_Dictionary> pPageDict = pPage->GetMutableDict();
212*3ac0a46fSAndroid Build Coastguard Worker   RetainPtr<CPDF_Object> pContentObj = GetPageContent(pPageDict.Get());
213*3ac0a46fSAndroid Build Coastguard Worker   if (!pContentObj)
214*3ac0a46fSAndroid Build Coastguard Worker     return false;
215*3ac0a46fSAndroid Build Coastguard Worker 
216*3ac0a46fSAndroid Build Coastguard Worker   CPDF_Document* pDoc = pPage->GetDocument();
217*3ac0a46fSAndroid Build Coastguard Worker   if (!pDoc)
218*3ac0a46fSAndroid Build Coastguard Worker     return false;
219*3ac0a46fSAndroid Build Coastguard Worker 
220*3ac0a46fSAndroid Build Coastguard Worker   fxcrt::ostringstream text_buf;
221*3ac0a46fSAndroid Build Coastguard Worker   text_buf << "q ";
222*3ac0a46fSAndroid Build Coastguard Worker 
223*3ac0a46fSAndroid Build Coastguard Worker   if (clipRect) {
224*3ac0a46fSAndroid Build Coastguard Worker     CFX_FloatRect rect = CFXFloatRectFromFSRectF(*clipRect);
225*3ac0a46fSAndroid Build Coastguard Worker     rect.Normalize();
226*3ac0a46fSAndroid Build Coastguard Worker     WriteRect(text_buf, rect) << " re W* n ";
227*3ac0a46fSAndroid Build Coastguard Worker   }
228*3ac0a46fSAndroid Build Coastguard Worker   if (matrix)
229*3ac0a46fSAndroid Build Coastguard Worker     WriteMatrix(text_buf, CFXMatrixFromFSMatrix(*matrix)) << " cm ";
230*3ac0a46fSAndroid Build Coastguard Worker 
231*3ac0a46fSAndroid Build Coastguard Worker   auto pStream = pDoc->NewIndirect<CPDF_Stream>(pDoc->New<CPDF_Dictionary>());
232*3ac0a46fSAndroid Build Coastguard Worker   pStream->SetDataFromStringstream(&text_buf);
233*3ac0a46fSAndroid Build Coastguard Worker 
234*3ac0a46fSAndroid Build Coastguard Worker   auto pEndStream =
235*3ac0a46fSAndroid Build Coastguard Worker       pDoc->NewIndirect<CPDF_Stream>(pDoc->New<CPDF_Dictionary>());
236*3ac0a46fSAndroid Build Coastguard Worker   pEndStream->SetData(ByteStringView(" Q").raw_span());
237*3ac0a46fSAndroid Build Coastguard Worker 
238*3ac0a46fSAndroid Build Coastguard Worker   RetainPtr<CPDF_Array> pContentArray = ToArray(pContentObj);
239*3ac0a46fSAndroid Build Coastguard Worker   if (pContentArray) {
240*3ac0a46fSAndroid Build Coastguard Worker     pContentArray->InsertNewAt<CPDF_Reference>(0, pDoc, pStream->GetObjNum());
241*3ac0a46fSAndroid Build Coastguard Worker     pContentArray->AppendNew<CPDF_Reference>(pDoc, pEndStream->GetObjNum());
242*3ac0a46fSAndroid Build Coastguard Worker   } else if (pContentObj->IsStream() && !pContentObj->IsInline()) {
243*3ac0a46fSAndroid Build Coastguard Worker     pContentArray = pDoc->NewIndirect<CPDF_Array>();
244*3ac0a46fSAndroid Build Coastguard Worker     pContentArray->AppendNew<CPDF_Reference>(pDoc, pStream->GetObjNum());
245*3ac0a46fSAndroid Build Coastguard Worker     pContentArray->AppendNew<CPDF_Reference>(pDoc, pContentObj->GetObjNum());
246*3ac0a46fSAndroid Build Coastguard Worker     pContentArray->AppendNew<CPDF_Reference>(pDoc, pEndStream->GetObjNum());
247*3ac0a46fSAndroid Build Coastguard Worker     pPageDict->SetNewFor<CPDF_Reference>(pdfium::page_object::kContents, pDoc,
248*3ac0a46fSAndroid Build Coastguard Worker                                          pContentArray->GetObjNum());
249*3ac0a46fSAndroid Build Coastguard Worker   }
250*3ac0a46fSAndroid Build Coastguard Worker 
251*3ac0a46fSAndroid Build Coastguard Worker   // Need to transform the patterns as well.
252*3ac0a46fSAndroid Build Coastguard Worker   RetainPtr<const CPDF_Dictionary> pRes =
253*3ac0a46fSAndroid Build Coastguard Worker       pPageDict->GetDictFor(pdfium::page_object::kResources);
254*3ac0a46fSAndroid Build Coastguard Worker   if (!pRes)
255*3ac0a46fSAndroid Build Coastguard Worker     return true;
256*3ac0a46fSAndroid Build Coastguard Worker 
257*3ac0a46fSAndroid Build Coastguard Worker   RetainPtr<const CPDF_Dictionary> pPatternDict = pRes->GetDictFor("Pattern");
258*3ac0a46fSAndroid Build Coastguard Worker   if (!pPatternDict)
259*3ac0a46fSAndroid Build Coastguard Worker     return true;
260*3ac0a46fSAndroid Build Coastguard Worker 
261*3ac0a46fSAndroid Build Coastguard Worker   CPDF_DictionaryLocker locker(pPatternDict);
262*3ac0a46fSAndroid Build Coastguard Worker   for (const auto& it : locker) {
263*3ac0a46fSAndroid Build Coastguard Worker     RetainPtr<CPDF_Object> pObj = it.second;
264*3ac0a46fSAndroid Build Coastguard Worker     if (pObj->IsReference())
265*3ac0a46fSAndroid Build Coastguard Worker       pObj = pObj->GetMutableDirect();
266*3ac0a46fSAndroid Build Coastguard Worker 
267*3ac0a46fSAndroid Build Coastguard Worker     RetainPtr<CPDF_Dictionary> pDict;
268*3ac0a46fSAndroid Build Coastguard Worker     if (pObj->IsDictionary())
269*3ac0a46fSAndroid Build Coastguard Worker       pDict.Reset(pObj->AsMutableDictionary());
270*3ac0a46fSAndroid Build Coastguard Worker     else if (CPDF_Stream* pObjStream = pObj->AsMutableStream())
271*3ac0a46fSAndroid Build Coastguard Worker       pDict = pObjStream->GetMutableDict();
272*3ac0a46fSAndroid Build Coastguard Worker     else
273*3ac0a46fSAndroid Build Coastguard Worker       continue;
274*3ac0a46fSAndroid Build Coastguard Worker 
275*3ac0a46fSAndroid Build Coastguard Worker     if (matrix) {
276*3ac0a46fSAndroid Build Coastguard Worker       CFX_Matrix m = CFXMatrixFromFSMatrix(*matrix);
277*3ac0a46fSAndroid Build Coastguard Worker       pDict->SetMatrixFor("Matrix", pDict->GetMatrixFor("Matrix") * m);
278*3ac0a46fSAndroid Build Coastguard Worker     }
279*3ac0a46fSAndroid Build Coastguard Worker   }
280*3ac0a46fSAndroid Build Coastguard Worker 
281*3ac0a46fSAndroid Build Coastguard Worker   return true;
282*3ac0a46fSAndroid Build Coastguard Worker }
283*3ac0a46fSAndroid Build Coastguard Worker 
284*3ac0a46fSAndroid Build Coastguard Worker FPDF_EXPORT void FPDF_CALLCONV
FPDFPageObj_TransformClipPath(FPDF_PAGEOBJECT page_object,double a,double b,double c,double d,double e,double f)285*3ac0a46fSAndroid Build Coastguard Worker FPDFPageObj_TransformClipPath(FPDF_PAGEOBJECT page_object,
286*3ac0a46fSAndroid Build Coastguard Worker                               double a,
287*3ac0a46fSAndroid Build Coastguard Worker                               double b,
288*3ac0a46fSAndroid Build Coastguard Worker                               double c,
289*3ac0a46fSAndroid Build Coastguard Worker                               double d,
290*3ac0a46fSAndroid Build Coastguard Worker                               double e,
291*3ac0a46fSAndroid Build Coastguard Worker                               double f) {
292*3ac0a46fSAndroid Build Coastguard Worker   CPDF_PageObject* pPageObj = CPDFPageObjectFromFPDFPageObject(page_object);
293*3ac0a46fSAndroid Build Coastguard Worker   if (!pPageObj)
294*3ac0a46fSAndroid Build Coastguard Worker     return;
295*3ac0a46fSAndroid Build Coastguard Worker 
296*3ac0a46fSAndroid Build Coastguard Worker   CFX_Matrix matrix((float)a, (float)b, (float)c, (float)d, (float)e, (float)f);
297*3ac0a46fSAndroid Build Coastguard Worker 
298*3ac0a46fSAndroid Build Coastguard Worker   // Special treatment to shading object, because the ClipPath for shading
299*3ac0a46fSAndroid Build Coastguard Worker   // object is already transformed.
300*3ac0a46fSAndroid Build Coastguard Worker   if (!pPageObj->IsShading())
301*3ac0a46fSAndroid Build Coastguard Worker     pPageObj->TransformClipPath(matrix);
302*3ac0a46fSAndroid Build Coastguard Worker   pPageObj->TransformGeneralState(matrix);
303*3ac0a46fSAndroid Build Coastguard Worker }
304*3ac0a46fSAndroid Build Coastguard Worker 
305*3ac0a46fSAndroid Build Coastguard Worker FPDF_EXPORT FPDF_CLIPPATH FPDF_CALLCONV
FPDFPageObj_GetClipPath(FPDF_PAGEOBJECT page_object)306*3ac0a46fSAndroid Build Coastguard Worker FPDFPageObj_GetClipPath(FPDF_PAGEOBJECT page_object) {
307*3ac0a46fSAndroid Build Coastguard Worker   CPDF_PageObject* pPageObj = CPDFPageObjectFromFPDFPageObject(page_object);
308*3ac0a46fSAndroid Build Coastguard Worker   if (!pPageObj)
309*3ac0a46fSAndroid Build Coastguard Worker     return nullptr;
310*3ac0a46fSAndroid Build Coastguard Worker 
311*3ac0a46fSAndroid Build Coastguard Worker   return FPDFClipPathFromCPDFClipPath(&pPageObj->m_ClipPath);
312*3ac0a46fSAndroid Build Coastguard Worker }
313*3ac0a46fSAndroid Build Coastguard Worker 
FPDFClipPath_CountPaths(FPDF_CLIPPATH clip_path)314*3ac0a46fSAndroid Build Coastguard Worker FPDF_EXPORT int FPDF_CALLCONV FPDFClipPath_CountPaths(FPDF_CLIPPATH clip_path) {
315*3ac0a46fSAndroid Build Coastguard Worker   CPDF_ClipPath* pClipPath = CPDFClipPathFromFPDFClipPath(clip_path);
316*3ac0a46fSAndroid Build Coastguard Worker   if (!pClipPath || !pClipPath->HasRef())
317*3ac0a46fSAndroid Build Coastguard Worker     return -1;
318*3ac0a46fSAndroid Build Coastguard Worker 
319*3ac0a46fSAndroid Build Coastguard Worker   return pdfium::base::checked_cast<int>(pClipPath->GetPathCount());
320*3ac0a46fSAndroid Build Coastguard Worker }
321*3ac0a46fSAndroid Build Coastguard Worker 
322*3ac0a46fSAndroid Build Coastguard Worker FPDF_EXPORT int FPDF_CALLCONV
FPDFClipPath_CountPathSegments(FPDF_CLIPPATH clip_path,int path_index)323*3ac0a46fSAndroid Build Coastguard Worker FPDFClipPath_CountPathSegments(FPDF_CLIPPATH clip_path, int path_index) {
324*3ac0a46fSAndroid Build Coastguard Worker   CPDF_ClipPath* pClipPath = CPDFClipPathFromFPDFClipPath(clip_path);
325*3ac0a46fSAndroid Build Coastguard Worker   if (!pClipPath || !pClipPath->HasRef())
326*3ac0a46fSAndroid Build Coastguard Worker     return -1;
327*3ac0a46fSAndroid Build Coastguard Worker 
328*3ac0a46fSAndroid Build Coastguard Worker   if (path_index < 0 ||
329*3ac0a46fSAndroid Build Coastguard Worker       static_cast<size_t>(path_index) >= pClipPath->GetPathCount()) {
330*3ac0a46fSAndroid Build Coastguard Worker     return -1;
331*3ac0a46fSAndroid Build Coastguard Worker   }
332*3ac0a46fSAndroid Build Coastguard Worker 
333*3ac0a46fSAndroid Build Coastguard Worker   return fxcrt::CollectionSize<int>(pClipPath->GetPath(path_index).GetPoints());
334*3ac0a46fSAndroid Build Coastguard Worker }
335*3ac0a46fSAndroid Build Coastguard Worker 
336*3ac0a46fSAndroid Build Coastguard Worker FPDF_EXPORT FPDF_PATHSEGMENT FPDF_CALLCONV
FPDFClipPath_GetPathSegment(FPDF_CLIPPATH clip_path,int path_index,int segment_index)337*3ac0a46fSAndroid Build Coastguard Worker FPDFClipPath_GetPathSegment(FPDF_CLIPPATH clip_path,
338*3ac0a46fSAndroid Build Coastguard Worker                             int path_index,
339*3ac0a46fSAndroid Build Coastguard Worker                             int segment_index) {
340*3ac0a46fSAndroid Build Coastguard Worker   CPDF_ClipPath* pClipPath = CPDFClipPathFromFPDFClipPath(clip_path);
341*3ac0a46fSAndroid Build Coastguard Worker   if (!pClipPath || !pClipPath->HasRef())
342*3ac0a46fSAndroid Build Coastguard Worker     return nullptr;
343*3ac0a46fSAndroid Build Coastguard Worker 
344*3ac0a46fSAndroid Build Coastguard Worker   if (path_index < 0 ||
345*3ac0a46fSAndroid Build Coastguard Worker       static_cast<size_t>(path_index) >= pClipPath->GetPathCount()) {
346*3ac0a46fSAndroid Build Coastguard Worker     return nullptr;
347*3ac0a46fSAndroid Build Coastguard Worker   }
348*3ac0a46fSAndroid Build Coastguard Worker 
349*3ac0a46fSAndroid Build Coastguard Worker   pdfium::span<const CFX_Path::Point> points =
350*3ac0a46fSAndroid Build Coastguard Worker       pClipPath->GetPath(path_index).GetPoints();
351*3ac0a46fSAndroid Build Coastguard Worker   if (!fxcrt::IndexInBounds(points, segment_index))
352*3ac0a46fSAndroid Build Coastguard Worker     return nullptr;
353*3ac0a46fSAndroid Build Coastguard Worker 
354*3ac0a46fSAndroid Build Coastguard Worker   return FPDFPathSegmentFromFXPathPoint(&points[segment_index]);
355*3ac0a46fSAndroid Build Coastguard Worker }
356*3ac0a46fSAndroid Build Coastguard Worker 
FPDF_CreateClipPath(float left,float bottom,float right,float top)357*3ac0a46fSAndroid Build Coastguard Worker FPDF_EXPORT FPDF_CLIPPATH FPDF_CALLCONV FPDF_CreateClipPath(float left,
358*3ac0a46fSAndroid Build Coastguard Worker                                                             float bottom,
359*3ac0a46fSAndroid Build Coastguard Worker                                                             float right,
360*3ac0a46fSAndroid Build Coastguard Worker                                                             float top) {
361*3ac0a46fSAndroid Build Coastguard Worker   CPDF_Path Path;
362*3ac0a46fSAndroid Build Coastguard Worker   Path.AppendRect(left, bottom, right, top);
363*3ac0a46fSAndroid Build Coastguard Worker 
364*3ac0a46fSAndroid Build Coastguard Worker   auto pNewClipPath = std::make_unique<CPDF_ClipPath>();
365*3ac0a46fSAndroid Build Coastguard Worker   pNewClipPath->AppendPath(Path, CFX_FillRenderOptions::FillType::kEvenOdd);
366*3ac0a46fSAndroid Build Coastguard Worker 
367*3ac0a46fSAndroid Build Coastguard Worker   // Caller takes ownership.
368*3ac0a46fSAndroid Build Coastguard Worker   return FPDFClipPathFromCPDFClipPath(pNewClipPath.release());
369*3ac0a46fSAndroid Build Coastguard Worker }
370*3ac0a46fSAndroid Build Coastguard Worker 
FPDF_DestroyClipPath(FPDF_CLIPPATH clipPath)371*3ac0a46fSAndroid Build Coastguard Worker FPDF_EXPORT void FPDF_CALLCONV FPDF_DestroyClipPath(FPDF_CLIPPATH clipPath) {
372*3ac0a46fSAndroid Build Coastguard Worker   // Take ownership back from caller and destroy.
373*3ac0a46fSAndroid Build Coastguard Worker   std::unique_ptr<CPDF_ClipPath>(CPDFClipPathFromFPDFClipPath(clipPath));
374*3ac0a46fSAndroid Build Coastguard Worker }
375*3ac0a46fSAndroid Build Coastguard Worker 
FPDFPage_InsertClipPath(FPDF_PAGE page,FPDF_CLIPPATH clipPath)376*3ac0a46fSAndroid Build Coastguard Worker FPDF_EXPORT void FPDF_CALLCONV FPDFPage_InsertClipPath(FPDF_PAGE page,
377*3ac0a46fSAndroid Build Coastguard Worker                                                        FPDF_CLIPPATH clipPath) {
378*3ac0a46fSAndroid Build Coastguard Worker   CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
379*3ac0a46fSAndroid Build Coastguard Worker   if (!pPage)
380*3ac0a46fSAndroid Build Coastguard Worker     return;
381*3ac0a46fSAndroid Build Coastguard Worker 
382*3ac0a46fSAndroid Build Coastguard Worker   RetainPtr<CPDF_Dictionary> pPageDict = pPage->GetMutableDict();
383*3ac0a46fSAndroid Build Coastguard Worker   RetainPtr<CPDF_Object> pContentObj = GetPageContent(pPageDict.Get());
384*3ac0a46fSAndroid Build Coastguard Worker   if (!pContentObj)
385*3ac0a46fSAndroid Build Coastguard Worker     return;
386*3ac0a46fSAndroid Build Coastguard Worker 
387*3ac0a46fSAndroid Build Coastguard Worker   fxcrt::ostringstream strClip;
388*3ac0a46fSAndroid Build Coastguard Worker   CPDF_ClipPath* pClipPath = CPDFClipPathFromFPDFClipPath(clipPath);
389*3ac0a46fSAndroid Build Coastguard Worker   for (size_t i = 0; i < pClipPath->GetPathCount(); ++i) {
390*3ac0a46fSAndroid Build Coastguard Worker     CPDF_Path path = pClipPath->GetPath(i);
391*3ac0a46fSAndroid Build Coastguard Worker     if (path.GetPoints().empty()) {
392*3ac0a46fSAndroid Build Coastguard Worker       // Empty clipping (totally clipped out)
393*3ac0a46fSAndroid Build Coastguard Worker       strClip << "0 0 m W n ";
394*3ac0a46fSAndroid Build Coastguard Worker     } else {
395*3ac0a46fSAndroid Build Coastguard Worker       OutputPath(strClip, path);
396*3ac0a46fSAndroid Build Coastguard Worker       if (pClipPath->GetClipType(i) ==
397*3ac0a46fSAndroid Build Coastguard Worker           CFX_FillRenderOptions::FillType::kWinding) {
398*3ac0a46fSAndroid Build Coastguard Worker         strClip << "W n\n";
399*3ac0a46fSAndroid Build Coastguard Worker       } else {
400*3ac0a46fSAndroid Build Coastguard Worker         strClip << "W* n\n";
401*3ac0a46fSAndroid Build Coastguard Worker       }
402*3ac0a46fSAndroid Build Coastguard Worker     }
403*3ac0a46fSAndroid Build Coastguard Worker   }
404*3ac0a46fSAndroid Build Coastguard Worker   CPDF_Document* pDoc = pPage->GetDocument();
405*3ac0a46fSAndroid Build Coastguard Worker   if (!pDoc)
406*3ac0a46fSAndroid Build Coastguard Worker     return;
407*3ac0a46fSAndroid Build Coastguard Worker 
408*3ac0a46fSAndroid Build Coastguard Worker   auto pStream = pDoc->NewIndirect<CPDF_Stream>(pDoc->New<CPDF_Dictionary>());
409*3ac0a46fSAndroid Build Coastguard Worker   pStream->SetDataFromStringstream(&strClip);
410*3ac0a46fSAndroid Build Coastguard Worker 
411*3ac0a46fSAndroid Build Coastguard Worker   RetainPtr<CPDF_Array> pArray = ToArray(pContentObj);
412*3ac0a46fSAndroid Build Coastguard Worker   if (pArray) {
413*3ac0a46fSAndroid Build Coastguard Worker     pArray->InsertNewAt<CPDF_Reference>(0, pDoc, pStream->GetObjNum());
414*3ac0a46fSAndroid Build Coastguard Worker   } else if (pContentObj->IsStream() && !pContentObj->IsInline()) {
415*3ac0a46fSAndroid Build Coastguard Worker     auto pContentArray = pDoc->NewIndirect<CPDF_Array>();
416*3ac0a46fSAndroid Build Coastguard Worker     pContentArray->AppendNew<CPDF_Reference>(pDoc, pStream->GetObjNum());
417*3ac0a46fSAndroid Build Coastguard Worker     pContentArray->AppendNew<CPDF_Reference>(pDoc, pContentObj->GetObjNum());
418*3ac0a46fSAndroid Build Coastguard Worker     pPageDict->SetNewFor<CPDF_Reference>(pdfium::page_object::kContents, pDoc,
419*3ac0a46fSAndroid Build Coastguard Worker                                          pContentArray->GetObjNum());
420*3ac0a46fSAndroid Build Coastguard Worker   }
421*3ac0a46fSAndroid Build Coastguard Worker }
422