xref: /aosp_15_r20/external/pdfium/fpdfsdk/fpdf_editpage.cpp (revision 3ac0a46f773bac49fa9476ec2b1cf3f8da5ec3a4)
1 // Copyright 2014 The PDFium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6 
7 #include "public/fpdf_edit.h"
8 
9 #include <algorithm>
10 #include <memory>
11 #include <utility>
12 #include <vector>
13 
14 #include "constants/page_object.h"
15 #include "core/fpdfapi/edit/cpdf_pagecontentgenerator.h"
16 #include "core/fpdfapi/page/cpdf_colorspace.h"
17 #include "core/fpdfapi/page/cpdf_docpagedata.h"
18 #include "core/fpdfapi/page/cpdf_form.h"
19 #include "core/fpdfapi/page/cpdf_formobject.h"
20 #include "core/fpdfapi/page/cpdf_imageobject.h"
21 #include "core/fpdfapi/page/cpdf_page.h"
22 #include "core/fpdfapi/page/cpdf_pageimagecache.h"
23 #include "core/fpdfapi/page/cpdf_pageobject.h"
24 #include "core/fpdfapi/page/cpdf_pathobject.h"
25 #include "core/fpdfapi/page/cpdf_shadingobject.h"
26 #include "core/fpdfapi/page/cpdf_textobject.h"
27 #include "core/fpdfapi/parser/cpdf_array.h"
28 #include "core/fpdfapi/parser/cpdf_dictionary.h"
29 #include "core/fpdfapi/parser/cpdf_document.h"
30 #include "core/fpdfapi/parser/cpdf_name.h"
31 #include "core/fpdfapi/parser/cpdf_number.h"
32 #include "core/fpdfapi/parser/cpdf_string.h"
33 #include "core/fpdfapi/render/cpdf_docrenderdata.h"
34 #include "core/fpdfdoc/cpdf_annot.h"
35 #include "core/fpdfdoc/cpdf_annotlist.h"
36 #include "core/fxcrt/fx_extension.h"
37 #include "core/fxcrt/fx_memcpy_wrappers.h"
38 #include "core/fxcrt/stl_util.h"
39 #include "fpdfsdk/cpdfsdk_helpers.h"
40 #include "public/fpdf_formfill.h"
41 #include "third_party/base/numerics/safe_conversions.h"
42 
43 #ifdef PDF_ENABLE_XFA
44 #include "fpdfsdk/fpdfxfa/cpdfxfa_context.h"
45 #include "fpdfsdk/fpdfxfa/cpdfxfa_page.h"
46 #endif  // PDF_ENABLE_XFA
47 
48 namespace {
49 
50 static_assert(FPDF_PAGEOBJ_TEXT ==
51                   static_cast<int>(CPDF_PageObject::Type::kText),
52               "FPDF_PAGEOBJ_TEXT/CPDF_PageObject::TEXT mismatch");
53 static_assert(FPDF_PAGEOBJ_PATH ==
54                   static_cast<int>(CPDF_PageObject::Type::kPath),
55               "FPDF_PAGEOBJ_PATH/CPDF_PageObject::PATH mismatch");
56 static_assert(FPDF_PAGEOBJ_IMAGE ==
57                   static_cast<int>(CPDF_PageObject::Type::kImage),
58               "FPDF_PAGEOBJ_IMAGE/CPDF_PageObject::IMAGE mismatch");
59 static_assert(FPDF_PAGEOBJ_SHADING ==
60                   static_cast<int>(CPDF_PageObject::Type::kShading),
61               "FPDF_PAGEOBJ_SHADING/CPDF_PageObject::SHADING mismatch");
62 static_assert(FPDF_PAGEOBJ_FORM ==
63                   static_cast<int>(CPDF_PageObject::Type::kForm),
64               "FPDF_PAGEOBJ_FORM/CPDF_PageObject::FORM mismatch");
65 
IsPageObject(CPDF_Page * pPage)66 bool IsPageObject(CPDF_Page* pPage) {
67   if (!pPage)
68     return false;
69 
70   RetainPtr<const CPDF_Dictionary> pFormDict = pPage->GetDict();
71   if (!pFormDict->KeyExist(pdfium::page_object::kType))
72     return false;
73 
74   RetainPtr<const CPDF_Name> pName =
75       ToName(pFormDict->GetObjectFor(pdfium::page_object::kType)->GetDirect());
76   return pName && pName->GetString() == "Page";
77 }
78 
CalcBoundingBox(CPDF_PageObject * pPageObj)79 void CalcBoundingBox(CPDF_PageObject* pPageObj) {
80   switch (pPageObj->GetType()) {
81     case CPDF_PageObject::Type::kText: {
82       break;
83     }
84     case CPDF_PageObject::Type::kPath: {
85       CPDF_PathObject* pPathObj = pPageObj->AsPath();
86       pPathObj->CalcBoundingBox();
87       break;
88     }
89     case CPDF_PageObject::Type::kImage: {
90       CPDF_ImageObject* pImageObj = pPageObj->AsImage();
91       pImageObj->CalcBoundingBox();
92       break;
93     }
94     case CPDF_PageObject::Type::kShading: {
95       CPDF_ShadingObject* pShadingObj = pPageObj->AsShading();
96       pShadingObj->CalcBoundingBox();
97       break;
98     }
99     case CPDF_PageObject::Type::kForm: {
100       CPDF_FormObject* pFormObj = pPageObj->AsForm();
101       pFormObj->CalcBoundingBox();
102       break;
103     }
104   }
105 }
106 
GetMarkParamDict(FPDF_PAGEOBJECTMARK mark)107 RetainPtr<CPDF_Dictionary> GetMarkParamDict(FPDF_PAGEOBJECTMARK mark) {
108   CPDF_ContentMarkItem* pMarkItem =
109       CPDFContentMarkItemFromFPDFPageObjectMark(mark);
110   return pMarkItem ? pMarkItem->GetParam() : nullptr;
111 }
112 
GetOrCreateMarkParamsDict(FPDF_DOCUMENT document,FPDF_PAGEOBJECTMARK mark)113 RetainPtr<CPDF_Dictionary> GetOrCreateMarkParamsDict(FPDF_DOCUMENT document,
114                                                      FPDF_PAGEOBJECTMARK mark) {
115   CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
116   if (!pDoc)
117     return nullptr;
118 
119   CPDF_ContentMarkItem* pMarkItem =
120       CPDFContentMarkItemFromFPDFPageObjectMark(mark);
121   if (!pMarkItem)
122     return nullptr;
123 
124   RetainPtr<CPDF_Dictionary> pParams = pMarkItem->GetParam();
125   if (!pParams) {
126     pParams = pDoc->New<CPDF_Dictionary>();
127     pMarkItem->SetDirectDict(pParams);
128   }
129   return pParams;
130 }
131 
PageObjectContainsMark(CPDF_PageObject * pPageObj,FPDF_PAGEOBJECTMARK mark)132 bool PageObjectContainsMark(CPDF_PageObject* pPageObj,
133                             FPDF_PAGEOBJECTMARK mark) {
134   const CPDF_ContentMarkItem* pMarkItem =
135       CPDFContentMarkItemFromFPDFPageObjectMark(mark);
136   return pMarkItem && pPageObj->GetContentMarks()->ContainsItem(pMarkItem);
137 }
138 
CPDFFormObjectFromFPDFPageObject(FPDF_PAGEOBJECT page_object)139 CPDF_FormObject* CPDFFormObjectFromFPDFPageObject(FPDF_PAGEOBJECT page_object) {
140   auto* pPageObj = CPDFPageObjectFromFPDFPageObject(page_object);
141   return pPageObj ? pPageObj->AsForm() : nullptr;
142 }
143 
CPDFPageObjHolderFromFPDFFormObject(FPDF_PAGEOBJECT page_object)144 const CPDF_PageObjectHolder* CPDFPageObjHolderFromFPDFFormObject(
145     FPDF_PAGEOBJECT page_object) {
146   CPDF_FormObject* pFormObject = CPDFFormObjectFromFPDFPageObject(page_object);
147   return pFormObject ? pFormObject->form() : nullptr;
148 }
149 
150 }  // namespace
151 
FPDF_CreateNewDocument()152 FPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV FPDF_CreateNewDocument() {
153   auto pDoc =
154       std::make_unique<CPDF_Document>(std::make_unique<CPDF_DocRenderData>(),
155                                       std::make_unique<CPDF_DocPageData>());
156   pDoc->CreateNewDoc();
157 
158   time_t currentTime;
159   ByteString DateStr;
160   if (IsPDFSandboxPolicyEnabled(FPDF_POLICY_MACHINETIME_ACCESS)) {
161     if (FXSYS_time(&currentTime) != -1) {
162       tm* pTM = FXSYS_localtime(&currentTime);
163       if (pTM) {
164         DateStr = ByteString::Format(
165             "D:%04d%02d%02d%02d%02d%02d", pTM->tm_year + 1900, pTM->tm_mon + 1,
166             pTM->tm_mday, pTM->tm_hour, pTM->tm_min, pTM->tm_sec);
167       }
168     }
169   }
170 
171   RetainPtr<CPDF_Dictionary> pInfoDict = pDoc->GetInfo();
172   if (pInfoDict) {
173     if (IsPDFSandboxPolicyEnabled(FPDF_POLICY_MACHINETIME_ACCESS))
174       pInfoDict->SetNewFor<CPDF_String>("CreationDate", DateStr, false);
175     pInfoDict->SetNewFor<CPDF_String>("Creator", L"PDFium");
176   }
177 
178   // Caller takes ownership of pDoc.
179   return FPDFDocumentFromCPDFDocument(pDoc.release());
180 }
181 
FPDFPage_Delete(FPDF_DOCUMENT document,int page_index)182 FPDF_EXPORT void FPDF_CALLCONV FPDFPage_Delete(FPDF_DOCUMENT document,
183                                                int page_index) {
184   auto* pDoc = CPDFDocumentFromFPDFDocument(document);
185   if (!pDoc)
186     return;
187 
188   CPDF_Document::Extension* pExtension = pDoc->GetExtension();
189   if (pExtension) {
190     pExtension->DeletePage(page_index);
191     return;
192   }
193 
194   pDoc->DeletePage(page_index);
195 }
196 
FPDFPage_New(FPDF_DOCUMENT document,int page_index,double width,double height)197 FPDF_EXPORT FPDF_PAGE FPDF_CALLCONV FPDFPage_New(FPDF_DOCUMENT document,
198                                                  int page_index,
199                                                  double width,
200                                                  double height) {
201   CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
202   if (!pDoc)
203     return nullptr;
204 
205   page_index = std::clamp(page_index, 0, pDoc->GetPageCount());
206   RetainPtr<CPDF_Dictionary> pPageDict(pDoc->CreateNewPage(page_index));
207   if (!pPageDict)
208     return nullptr;
209 
210   pPageDict->SetRectFor(pdfium::page_object::kMediaBox,
211                         CFX_FloatRect(0, 0, width, height));
212   pPageDict->SetNewFor<CPDF_Number>(pdfium::page_object::kRotate, 0);
213   pPageDict->SetNewFor<CPDF_Dictionary>(pdfium::page_object::kResources);
214 
215 #ifdef PDF_ENABLE_XFA
216   if (pDoc->GetExtension()) {
217     auto pXFAPage = pdfium::MakeRetain<CPDFXFA_Page>(pDoc, page_index);
218     pXFAPage->LoadPDFPageFromDict(pPageDict);
219     return FPDFPageFromIPDFPage(pXFAPage.Leak());  // Caller takes ownership.
220   }
221 #endif  // PDF_ENABLE_XFA
222 
223   auto pPage = pdfium::MakeRetain<CPDF_Page>(pDoc, pPageDict);
224   pPage->AddPageImageCache();
225   pPage->ParseContent();
226 
227   return FPDFPageFromIPDFPage(pPage.Leak());  // Caller takes ownership.
228 }
229 
FPDFPage_GetRotation(FPDF_PAGE page)230 FPDF_EXPORT int FPDF_CALLCONV FPDFPage_GetRotation(FPDF_PAGE page) {
231   CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
232   return IsPageObject(pPage) ? pPage->GetPageRotation() : -1;
233 }
234 
FPDFPage_InsertObject(FPDF_PAGE page,FPDF_PAGEOBJECT page_obj)235 FPDF_EXPORT void FPDF_CALLCONV FPDFPage_InsertObject(FPDF_PAGE page,
236                                                      FPDF_PAGEOBJECT page_obj) {
237   CPDF_PageObject* pPageObj = CPDFPageObjectFromFPDFPageObject(page_obj);
238   if (!pPageObj)
239     return;
240 
241   std::unique_ptr<CPDF_PageObject> pPageObjHolder(pPageObj);
242   CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
243   if (!IsPageObject(pPage))
244     return;
245 
246   pPageObj->SetDirty(true);
247   pPage->AppendPageObject(std::move(pPageObjHolder));
248   CalcBoundingBox(pPageObj);
249 }
250 
251 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDFPage_RemoveObject(FPDF_PAGE page,FPDF_PAGEOBJECT page_obj)252 FPDFPage_RemoveObject(FPDF_PAGE page, FPDF_PAGEOBJECT page_obj) {
253   CPDF_PageObject* pPageObj = CPDFPageObjectFromFPDFPageObject(page_obj);
254   if (!pPageObj)
255     return false;
256 
257   CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
258   if (!IsPageObject(pPage))
259     return false;
260 
261   // Caller takes ownership.
262   return !!pPage->RemovePageObject(pPageObj).release();
263 }
264 
FPDFPage_CountObjects(FPDF_PAGE page)265 FPDF_EXPORT int FPDF_CALLCONV FPDFPage_CountObjects(FPDF_PAGE page) {
266   CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
267   if (!IsPageObject(pPage))
268     return -1;
269 
270   return pdfium::base::checked_cast<int>(pPage->GetPageObjectCount());
271 }
272 
FPDFPage_GetObject(FPDF_PAGE page,int index)273 FPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV FPDFPage_GetObject(FPDF_PAGE page,
274                                                              int index) {
275   CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
276   if (!IsPageObject(pPage))
277     return nullptr;
278 
279   return FPDFPageObjectFromCPDFPageObject(pPage->GetPageObjectByIndex(index));
280 }
281 
FPDFPage_HasTransparency(FPDF_PAGE page)282 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_HasTransparency(FPDF_PAGE page) {
283   CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
284   return pPage && pPage->BackgroundAlphaNeeded();
285 }
286 
FPDFPageObj_Destroy(FPDF_PAGEOBJECT page_obj)287 FPDF_EXPORT void FPDF_CALLCONV FPDFPageObj_Destroy(FPDF_PAGEOBJECT page_obj) {
288   delete CPDFPageObjectFromFPDFPageObject(page_obj);
289 }
290 
291 FPDF_EXPORT int FPDF_CALLCONV
FPDFPageObj_CountMarks(FPDF_PAGEOBJECT page_object)292 FPDFPageObj_CountMarks(FPDF_PAGEOBJECT page_object) {
293   CPDF_PageObject* pPageObj = CPDFPageObjectFromFPDFPageObject(page_object);
294   if (!pPageObj)
295     return -1;
296 
297   return pdfium::base::checked_cast<int>(
298       pPageObj->GetContentMarks()->CountItems());
299 }
300 
301 FPDF_EXPORT FPDF_PAGEOBJECTMARK FPDF_CALLCONV
FPDFPageObj_GetMark(FPDF_PAGEOBJECT page_object,unsigned long index)302 FPDFPageObj_GetMark(FPDF_PAGEOBJECT page_object, unsigned long index) {
303   CPDF_PageObject* pPageObj = CPDFPageObjectFromFPDFPageObject(page_object);
304   if (!pPageObj)
305     return nullptr;
306 
307   CPDF_ContentMarks* pMarks = pPageObj->GetContentMarks();
308   if (index >= pMarks->CountItems())
309     return nullptr;
310 
311   return FPDFPageObjectMarkFromCPDFContentMarkItem(pMarks->GetItem(index));
312 }
313 
314 FPDF_EXPORT FPDF_PAGEOBJECTMARK FPDF_CALLCONV
FPDFPageObj_AddMark(FPDF_PAGEOBJECT page_object,FPDF_BYTESTRING name)315 FPDFPageObj_AddMark(FPDF_PAGEOBJECT page_object, FPDF_BYTESTRING name) {
316   CPDF_PageObject* pPageObj = CPDFPageObjectFromFPDFPageObject(page_object);
317   if (!pPageObj)
318     return nullptr;
319 
320   CPDF_ContentMarks* pMarks = pPageObj->GetContentMarks();
321   pMarks->AddMark(name);
322   pPageObj->SetDirty(true);
323 
324   const size_t index = pMarks->CountItems() - 1;
325   return FPDFPageObjectMarkFromCPDFContentMarkItem(pMarks->GetItem(index));
326 }
327 
328 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDFPageObj_RemoveMark(FPDF_PAGEOBJECT page_object,FPDF_PAGEOBJECTMARK mark)329 FPDFPageObj_RemoveMark(FPDF_PAGEOBJECT page_object, FPDF_PAGEOBJECTMARK mark) {
330   CPDF_PageObject* pPageObj = CPDFPageObjectFromFPDFPageObject(page_object);
331   CPDF_ContentMarkItem* pMarkItem =
332       CPDFContentMarkItemFromFPDFPageObjectMark(mark);
333   if (!pPageObj || !pMarkItem)
334     return false;
335 
336   if (!pPageObj->GetContentMarks()->RemoveMark(pMarkItem))
337     return false;
338 
339   pPageObj->SetDirty(true);
340   return true;
341 }
342 
343 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDFPageObjMark_GetName(FPDF_PAGEOBJECTMARK mark,void * buffer,unsigned long buflen,unsigned long * out_buflen)344 FPDFPageObjMark_GetName(FPDF_PAGEOBJECTMARK mark,
345                         void* buffer,
346                         unsigned long buflen,
347                         unsigned long* out_buflen) {
348   const CPDF_ContentMarkItem* pMarkItem =
349       CPDFContentMarkItemFromFPDFPageObjectMark(mark);
350   if (!pMarkItem || !out_buflen)
351     return false;
352 
353   *out_buflen = Utf16EncodeMaybeCopyAndReturnLength(
354       WideString::FromUTF8(pMarkItem->GetName().AsStringView()), buffer,
355       buflen);
356   return true;
357 }
358 
359 FPDF_EXPORT int FPDF_CALLCONV
FPDFPageObjMark_CountParams(FPDF_PAGEOBJECTMARK mark)360 FPDFPageObjMark_CountParams(FPDF_PAGEOBJECTMARK mark) {
361   const CPDF_ContentMarkItem* pMarkItem =
362       CPDFContentMarkItemFromFPDFPageObjectMark(mark);
363   if (!pMarkItem)
364     return -1;
365 
366   RetainPtr<const CPDF_Dictionary> pParams = pMarkItem->GetParam();
367   return pParams ? fxcrt::CollectionSize<int>(*pParams) : 0;
368 }
369 
370 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDFPageObjMark_GetParamKey(FPDF_PAGEOBJECTMARK mark,unsigned long index,void * buffer,unsigned long buflen,unsigned long * out_buflen)371 FPDFPageObjMark_GetParamKey(FPDF_PAGEOBJECTMARK mark,
372                             unsigned long index,
373                             void* buffer,
374                             unsigned long buflen,
375                             unsigned long* out_buflen) {
376   if (!out_buflen)
377     return false;
378 
379   RetainPtr<const CPDF_Dictionary> pParams = GetMarkParamDict(mark);
380   if (!pParams)
381     return false;
382 
383   CPDF_DictionaryLocker locker(pParams);
384   for (auto& it : locker) {
385     if (index == 0) {
386       *out_buflen = Utf16EncodeMaybeCopyAndReturnLength(
387           WideString::FromUTF8(it.first.AsStringView()), buffer, buflen);
388       return true;
389     }
390     --index;
391   }
392 
393   return false;
394 }
395 
396 FPDF_EXPORT FPDF_OBJECT_TYPE FPDF_CALLCONV
FPDFPageObjMark_GetParamValueType(FPDF_PAGEOBJECTMARK mark,FPDF_BYTESTRING key)397 FPDFPageObjMark_GetParamValueType(FPDF_PAGEOBJECTMARK mark,
398                                   FPDF_BYTESTRING key) {
399   RetainPtr<const CPDF_Dictionary> pParams = GetMarkParamDict(mark);
400   if (!pParams)
401     return FPDF_OBJECT_UNKNOWN;
402 
403   RetainPtr<const CPDF_Object> pObject = pParams->GetObjectFor(key);
404   return pObject ? pObject->GetType() : FPDF_OBJECT_UNKNOWN;
405 }
406 
407 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDFPageObjMark_GetParamIntValue(FPDF_PAGEOBJECTMARK mark,FPDF_BYTESTRING key,int * out_value)408 FPDFPageObjMark_GetParamIntValue(FPDF_PAGEOBJECTMARK mark,
409                                  FPDF_BYTESTRING key,
410                                  int* out_value) {
411   if (!out_value)
412     return false;
413 
414   RetainPtr<const CPDF_Dictionary> pParams = GetMarkParamDict(mark);
415   if (!pParams)
416     return false;
417 
418   RetainPtr<const CPDF_Object> pObj = pParams->GetObjectFor(key);
419   if (!pObj || !pObj->IsNumber())
420     return false;
421 
422   *out_value = pObj->GetInteger();
423   return true;
424 }
425 
426 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDFPageObjMark_GetParamStringValue(FPDF_PAGEOBJECTMARK mark,FPDF_BYTESTRING key,void * buffer,unsigned long buflen,unsigned long * out_buflen)427 FPDFPageObjMark_GetParamStringValue(FPDF_PAGEOBJECTMARK mark,
428                                     FPDF_BYTESTRING key,
429                                     void* buffer,
430                                     unsigned long buflen,
431                                     unsigned long* out_buflen) {
432   if (!out_buflen)
433     return false;
434 
435   RetainPtr<const CPDF_Dictionary> pParams = GetMarkParamDict(mark);
436   if (!pParams)
437     return false;
438 
439   RetainPtr<const CPDF_Object> pObj = pParams->GetObjectFor(key);
440   if (!pObj || !pObj->IsString())
441     return false;
442 
443   *out_buflen = Utf16EncodeMaybeCopyAndReturnLength(
444       WideString::FromUTF8(pObj->GetString().AsStringView()), buffer, buflen);
445   return true;
446 }
447 
448 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDFPageObjMark_GetParamBlobValue(FPDF_PAGEOBJECTMARK mark,FPDF_BYTESTRING key,void * buffer,unsigned long buflen,unsigned long * out_buflen)449 FPDFPageObjMark_GetParamBlobValue(FPDF_PAGEOBJECTMARK mark,
450                                   FPDF_BYTESTRING key,
451                                   void* buffer,
452                                   unsigned long buflen,
453                                   unsigned long* out_buflen) {
454   if (!out_buflen)
455     return false;
456 
457   RetainPtr<const CPDF_Dictionary> pParams = GetMarkParamDict(mark);
458   if (!pParams)
459     return false;
460 
461   RetainPtr<const CPDF_Object> pObj = pParams->GetObjectFor(key);
462   if (!pObj || !pObj->IsString())
463     return false;
464 
465   ByteString result = pObj->GetString();
466   const unsigned long len =
467       pdfium::base::checked_cast<unsigned long>(result.GetLength());
468 
469   if (buffer && len <= buflen)
470     memcpy(buffer, result.c_str(), len);
471 
472   *out_buflen = len;
473   return true;
474 }
475 
476 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDFPageObj_HasTransparency(FPDF_PAGEOBJECT page_object)477 FPDFPageObj_HasTransparency(FPDF_PAGEOBJECT page_object) {
478   CPDF_PageObject* pPageObj = CPDFPageObjectFromFPDFPageObject(page_object);
479   if (!pPageObj)
480     return false;
481 
482   if (pPageObj->m_GeneralState.GetBlendType() != BlendMode::kNormal)
483     return true;
484 
485   if (pPageObj->m_GeneralState.GetSoftMask())
486     return true;
487 
488   if (pPageObj->m_GeneralState.GetFillAlpha() != 1.0f)
489     return true;
490 
491   if (pPageObj->IsPath() && pPageObj->m_GeneralState.GetStrokeAlpha() != 1.0f)
492     return true;
493 
494   if (!pPageObj->IsForm())
495     return false;
496 
497   const CPDF_Form* pForm = pPageObj->AsForm()->form();
498   if (!pForm)
499     return false;
500 
501   const CPDF_Transparency& trans = pForm->GetTransparency();
502   return trans.IsGroup() || trans.IsIsolated();
503 }
504 
505 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDFPageObjMark_SetIntParam(FPDF_DOCUMENT document,FPDF_PAGEOBJECT page_object,FPDF_PAGEOBJECTMARK mark,FPDF_BYTESTRING key,int value)506 FPDFPageObjMark_SetIntParam(FPDF_DOCUMENT document,
507                             FPDF_PAGEOBJECT page_object,
508                             FPDF_PAGEOBJECTMARK mark,
509                             FPDF_BYTESTRING key,
510                             int value) {
511   CPDF_PageObject* pPageObj = CPDFPageObjectFromFPDFPageObject(page_object);
512   if (!pPageObj || !PageObjectContainsMark(pPageObj, mark))
513     return false;
514 
515   RetainPtr<CPDF_Dictionary> pParams =
516       GetOrCreateMarkParamsDict(document, mark);
517   if (!pParams)
518     return false;
519 
520   pParams->SetNewFor<CPDF_Number>(key, value);
521   pPageObj->SetDirty(true);
522   return true;
523 }
524 
525 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDFPageObjMark_SetStringParam(FPDF_DOCUMENT document,FPDF_PAGEOBJECT page_object,FPDF_PAGEOBJECTMARK mark,FPDF_BYTESTRING key,FPDF_BYTESTRING value)526 FPDFPageObjMark_SetStringParam(FPDF_DOCUMENT document,
527                                FPDF_PAGEOBJECT page_object,
528                                FPDF_PAGEOBJECTMARK mark,
529                                FPDF_BYTESTRING key,
530                                FPDF_BYTESTRING value) {
531   CPDF_PageObject* pPageObj = CPDFPageObjectFromFPDFPageObject(page_object);
532   if (!pPageObj || !PageObjectContainsMark(pPageObj, mark))
533     return false;
534 
535   RetainPtr<CPDF_Dictionary> pParams =
536       GetOrCreateMarkParamsDict(document, mark);
537   if (!pParams)
538     return false;
539 
540   pParams->SetNewFor<CPDF_String>(key, value, false);
541   pPageObj->SetDirty(true);
542   return true;
543 }
544 
545 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDFPageObjMark_SetBlobParam(FPDF_DOCUMENT document,FPDF_PAGEOBJECT page_object,FPDF_PAGEOBJECTMARK mark,FPDF_BYTESTRING key,void * value,unsigned long value_len)546 FPDFPageObjMark_SetBlobParam(FPDF_DOCUMENT document,
547                              FPDF_PAGEOBJECT page_object,
548                              FPDF_PAGEOBJECTMARK mark,
549                              FPDF_BYTESTRING key,
550                              void* value,
551                              unsigned long value_len) {
552   CPDF_PageObject* pPageObj = CPDFPageObjectFromFPDFPageObject(page_object);
553   if (!pPageObj || !PageObjectContainsMark(pPageObj, mark))
554     return false;
555 
556   RetainPtr<CPDF_Dictionary> pParams =
557       GetOrCreateMarkParamsDict(document, mark);
558   if (!pParams)
559     return false;
560 
561   if (!value && value_len > 0)
562     return false;
563 
564   pParams->SetNewFor<CPDF_String>(
565       key, ByteString(static_cast<const char*>(value), value_len), true);
566   pPageObj->SetDirty(true);
567   return true;
568 }
569 
570 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDFPageObjMark_RemoveParam(FPDF_PAGEOBJECT page_object,FPDF_PAGEOBJECTMARK mark,FPDF_BYTESTRING key)571 FPDFPageObjMark_RemoveParam(FPDF_PAGEOBJECT page_object,
572                             FPDF_PAGEOBJECTMARK mark,
573                             FPDF_BYTESTRING key) {
574   CPDF_PageObject* pPageObj = CPDFPageObjectFromFPDFPageObject(page_object);
575   if (!pPageObj)
576     return false;
577 
578   RetainPtr<CPDF_Dictionary> pParams = GetMarkParamDict(mark);
579   if (!pParams)
580     return false;
581 
582   auto removed = pParams->RemoveFor(key);
583   if (!removed)
584     return false;
585 
586   pPageObj->SetDirty(true);
587   return true;
588 }
589 
FPDFPageObj_GetType(FPDF_PAGEOBJECT page_object)590 FPDF_EXPORT int FPDF_CALLCONV FPDFPageObj_GetType(FPDF_PAGEOBJECT page_object) {
591   CPDF_PageObject* pPageObj = CPDFPageObjectFromFPDFPageObject(page_object);
592   return pPageObj ? static_cast<int>(pPageObj->GetType())
593                   : FPDF_PAGEOBJ_UNKNOWN;
594 }
595 
FPDFPage_GenerateContent(FPDF_PAGE page)596 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_GenerateContent(FPDF_PAGE page) {
597   CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
598   if (!IsPageObject(pPage))
599     return false;
600 
601   CPDF_PageContentGenerator CG(pPage);
602   CG.GenerateContent();
603   return true;
604 }
605 
606 FPDF_EXPORT void FPDF_CALLCONV
FPDFPageObj_Transform(FPDF_PAGEOBJECT page_object,double a,double b,double c,double d,double e,double f)607 FPDFPageObj_Transform(FPDF_PAGEOBJECT page_object,
608                       double a,
609                       double b,
610                       double c,
611                       double d,
612                       double e,
613                       double f) {
614   CPDF_PageObject* pPageObj = CPDFPageObjectFromFPDFPageObject(page_object);
615   if (!pPageObj)
616     return;
617 
618   CFX_Matrix matrix((float)a, (float)b, (float)c, (float)d, (float)e, (float)f);
619   pPageObj->Transform(matrix);
620 }
621 
622 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDFPageObj_GetMatrix(FPDF_PAGEOBJECT page_object,FS_MATRIX * matrix)623 FPDFPageObj_GetMatrix(FPDF_PAGEOBJECT page_object, FS_MATRIX* matrix) {
624   CPDF_PageObject* pPageObj = CPDFPageObjectFromFPDFPageObject(page_object);
625   if (!pPageObj || !matrix)
626     return false;
627 
628   switch (pPageObj->GetType()) {
629     case CPDF_PageObject::Type::kText:
630       *matrix = FSMatrixFromCFXMatrix(pPageObj->AsText()->GetTextMatrix());
631       return true;
632     case CPDF_PageObject::Type::kPath:
633       *matrix = FSMatrixFromCFXMatrix(pPageObj->AsPath()->matrix());
634       return true;
635     case CPDF_PageObject::Type::kImage:
636       *matrix = FSMatrixFromCFXMatrix(pPageObj->AsImage()->matrix());
637       return true;
638     case CPDF_PageObject::Type::kShading:
639       return false;
640     case CPDF_PageObject::Type::kForm:
641       *matrix = FSMatrixFromCFXMatrix(pPageObj->AsForm()->form_matrix());
642       return true;
643   }
644 }
645 
646 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDFPageObj_SetMatrix(FPDF_PAGEOBJECT page_object,const FS_MATRIX * matrix)647 FPDFPageObj_SetMatrix(FPDF_PAGEOBJECT page_object, const FS_MATRIX* matrix) {
648   CPDF_PageObject* pPageObj = CPDFPageObjectFromFPDFPageObject(page_object);
649   if (!pPageObj || !matrix)
650     return false;
651 
652   CFX_Matrix cmatrix = CFXMatrixFromFSMatrix(*matrix);
653   switch (pPageObj->GetType()) {
654     case CPDF_PageObject::Type::kText:
655       pPageObj->AsText()->SetTextMatrix(cmatrix);
656       break;
657     case CPDF_PageObject::Type::kPath:
658       pPageObj->AsPath()->SetPathMatrix(cmatrix);
659       break;
660     case CPDF_PageObject::Type::kImage:
661       pPageObj->AsImage()->SetImageMatrix(cmatrix);
662       break;
663     case CPDF_PageObject::Type::kShading:
664       return false;
665     case CPDF_PageObject::Type::kForm:
666       pPageObj->AsForm()->SetFormMatrix(cmatrix);
667       break;
668   }
669   pPageObj->SetDirty(true);
670   return true;
671 }
672 
673 FPDF_EXPORT void FPDF_CALLCONV
FPDFPageObj_SetBlendMode(FPDF_PAGEOBJECT page_object,FPDF_BYTESTRING blend_mode)674 FPDFPageObj_SetBlendMode(FPDF_PAGEOBJECT page_object,
675                          FPDF_BYTESTRING blend_mode) {
676   CPDF_PageObject* pPageObj = CPDFPageObjectFromFPDFPageObject(page_object);
677   if (!pPageObj)
678     return;
679 
680   pPageObj->m_GeneralState.SetBlendMode(blend_mode);
681   pPageObj->SetDirty(true);
682 }
683 
FPDFPage_TransformAnnots(FPDF_PAGE page,double a,double b,double c,double d,double e,double f)684 FPDF_EXPORT void FPDF_CALLCONV FPDFPage_TransformAnnots(FPDF_PAGE page,
685                                                         double a,
686                                                         double b,
687                                                         double c,
688                                                         double d,
689                                                         double e,
690                                                         double f) {
691   CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
692   if (!pPage)
693     return;
694 
695   CPDF_AnnotList AnnotList(pPage);
696   for (size_t i = 0; i < AnnotList.Count(); ++i) {
697     CPDF_Annot* pAnnot = AnnotList.GetAt(i);
698     CFX_Matrix matrix((float)a, (float)b, (float)c, (float)d, (float)e,
699                       (float)f);
700     CFX_FloatRect rect = matrix.TransformRect(pAnnot->GetRect());
701 
702     RetainPtr<CPDF_Dictionary> pAnnotDict = pAnnot->GetMutableAnnotDict();
703     RetainPtr<CPDF_Array> pRectArray = pAnnotDict->GetMutableArrayFor("Rect");
704     if (pRectArray)
705       pRectArray->Clear();
706     else
707       pRectArray = pAnnotDict->SetNewFor<CPDF_Array>("Rect");
708 
709     pRectArray->AppendNew<CPDF_Number>(rect.left);
710     pRectArray->AppendNew<CPDF_Number>(rect.bottom);
711     pRectArray->AppendNew<CPDF_Number>(rect.right);
712     pRectArray->AppendNew<CPDF_Number>(rect.top);
713 
714     // TODO(unknown): Transform AP's rectangle
715   }
716 }
717 
FPDFPage_SetRotation(FPDF_PAGE page,int rotate)718 FPDF_EXPORT void FPDF_CALLCONV FPDFPage_SetRotation(FPDF_PAGE page,
719                                                     int rotate) {
720   CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
721   if (!IsPageObject(pPage))
722     return;
723 
724   rotate %= 4;
725   pPage->GetMutableDict()->SetNewFor<CPDF_Number>(pdfium::page_object::kRotate,
726                                                   rotate * 90);
727   pPage->UpdateDimensions();
728 }
729 
FPDFPageObj_SetFillColor(FPDF_PAGEOBJECT page_object,unsigned int R,unsigned int G,unsigned int B,unsigned int A)730 FPDF_BOOL FPDFPageObj_SetFillColor(FPDF_PAGEOBJECT page_object,
731                                    unsigned int R,
732                                    unsigned int G,
733                                    unsigned int B,
734                                    unsigned int A) {
735   CPDF_PageObject* pPageObj = CPDFPageObjectFromFPDFPageObject(page_object);
736   if (!pPageObj || R > 255 || G > 255 || B > 255 || A > 255)
737     return false;
738 
739   std::vector<float> rgb = {R / 255.f, G / 255.f, B / 255.f};
740   pPageObj->m_GeneralState.SetFillAlpha(A / 255.f);
741   pPageObj->m_ColorState.SetFillColor(
742       CPDF_ColorSpace::GetStockCS(CPDF_ColorSpace::Family::kDeviceRGB),
743       std::move(rgb));
744   pPageObj->SetDirty(true);
745   return true;
746 }
747 
748 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDFPageObj_GetFillColor(FPDF_PAGEOBJECT page_object,unsigned int * R,unsigned int * G,unsigned int * B,unsigned int * A)749 FPDFPageObj_GetFillColor(FPDF_PAGEOBJECT page_object,
750                          unsigned int* R,
751                          unsigned int* G,
752                          unsigned int* B,
753                          unsigned int* A) {
754   auto* pPageObj = CPDFPageObjectFromFPDFPageObject(page_object);
755   if (!pPageObj || !R || !G || !B || !A)
756     return false;
757 
758   if (!pPageObj->m_ColorState.HasRef())
759     return false;
760 
761   FX_COLORREF fill_color = pPageObj->m_ColorState.GetFillColorRef();
762   *R = FXSYS_GetRValue(fill_color);
763   *G = FXSYS_GetGValue(fill_color);
764   *B = FXSYS_GetBValue(fill_color);
765   *A = FXSYS_GetUnsignedAlpha(pPageObj->m_GeneralState.GetFillAlpha());
766   return true;
767 }
768 
769 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDFPageObj_GetBounds(FPDF_PAGEOBJECT page_object,float * left,float * bottom,float * right,float * top)770 FPDFPageObj_GetBounds(FPDF_PAGEOBJECT page_object,
771                       float* left,
772                       float* bottom,
773                       float* right,
774                       float* top) {
775   CPDF_PageObject* pPageObj = CPDFPageObjectFromFPDFPageObject(page_object);
776   if (!pPageObj)
777     return false;
778 
779   const CFX_FloatRect& bbox = pPageObj->GetRect();
780   *left = bbox.left;
781   *bottom = bbox.bottom;
782   *right = bbox.right;
783   *top = bbox.top;
784   return true;
785 }
786 
787 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDFPageObj_GetRotatedBounds(FPDF_PAGEOBJECT page_object,FS_QUADPOINTSF * quad_points)788 FPDFPageObj_GetRotatedBounds(FPDF_PAGEOBJECT page_object,
789                              FS_QUADPOINTSF* quad_points) {
790   CPDF_PageObject* cpage_object = CPDFPageObjectFromFPDFPageObject(page_object);
791   if (!cpage_object || !quad_points)
792     return false;
793 
794   CFX_Matrix matrix;
795   switch (cpage_object->GetType()) {
796     case CPDF_PageObject::Type::kText:
797       matrix = cpage_object->AsText()->GetTextMatrix();
798       break;
799     case CPDF_PageObject::Type::kImage:
800       matrix = cpage_object->AsImage()->matrix();
801       break;
802     default:
803       // TODO(crbug.com/pdfium/1840): Support more object types.
804       return false;
805   }
806 
807   const CFX_FloatRect& bbox = cpage_object->GetOriginalRect();
808   const CFX_PointF bottom_left = matrix.Transform({bbox.left, bbox.bottom});
809   const CFX_PointF bottom_right = matrix.Transform({bbox.right, bbox.bottom});
810   const CFX_PointF top_right = matrix.Transform({bbox.right, bbox.top});
811   const CFX_PointF top_left = matrix.Transform({bbox.left, bbox.top});
812 
813   // See PDF 32000-1:2008, figure 64 for the QuadPoints ordering.
814   quad_points->x1 = bottom_left.x;
815   quad_points->y1 = bottom_left.y;
816   quad_points->x2 = bottom_right.x;
817   quad_points->y2 = bottom_right.y;
818   quad_points->x3 = top_right.x;
819   quad_points->y3 = top_right.y;
820   quad_points->x4 = top_left.x;
821   quad_points->y4 = top_left.y;
822   return true;
823 }
824 
825 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDFPageObj_SetStrokeColor(FPDF_PAGEOBJECT page_object,unsigned int R,unsigned int G,unsigned int B,unsigned int A)826 FPDFPageObj_SetStrokeColor(FPDF_PAGEOBJECT page_object,
827                            unsigned int R,
828                            unsigned int G,
829                            unsigned int B,
830                            unsigned int A) {
831   auto* pPageObj = CPDFPageObjectFromFPDFPageObject(page_object);
832   if (!pPageObj || R > 255 || G > 255 || B > 255 || A > 255)
833     return false;
834 
835   std::vector<float> rgb = {R / 255.f, G / 255.f, B / 255.f};
836   pPageObj->m_GeneralState.SetStrokeAlpha(A / 255.f);
837   pPageObj->m_ColorState.SetStrokeColor(
838       CPDF_ColorSpace::GetStockCS(CPDF_ColorSpace::Family::kDeviceRGB),
839       std::move(rgb));
840   pPageObj->SetDirty(true);
841   return true;
842 }
843 
844 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDFPageObj_GetStrokeColor(FPDF_PAGEOBJECT page_object,unsigned int * R,unsigned int * G,unsigned int * B,unsigned int * A)845 FPDFPageObj_GetStrokeColor(FPDF_PAGEOBJECT page_object,
846                            unsigned int* R,
847                            unsigned int* G,
848                            unsigned int* B,
849                            unsigned int* A) {
850   auto* pPageObj = CPDFPageObjectFromFPDFPageObject(page_object);
851   if (!pPageObj || !R || !G || !B || !A)
852     return false;
853 
854   if (!pPageObj->m_ColorState.HasRef())
855     return false;
856 
857   FX_COLORREF stroke_color = pPageObj->m_ColorState.GetStrokeColorRef();
858   *R = FXSYS_GetRValue(stroke_color);
859   *G = FXSYS_GetGValue(stroke_color);
860   *B = FXSYS_GetBValue(stroke_color);
861   *A = FXSYS_GetUnsignedAlpha(pPageObj->m_GeneralState.GetStrokeAlpha());
862   return true;
863 }
864 
865 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDFPageObj_SetStrokeWidth(FPDF_PAGEOBJECT page_object,float width)866 FPDFPageObj_SetStrokeWidth(FPDF_PAGEOBJECT page_object, float width) {
867   auto* pPageObj = CPDFPageObjectFromFPDFPageObject(page_object);
868   if (!pPageObj || width < 0.0f)
869     return false;
870 
871   pPageObj->m_GraphState.SetLineWidth(width);
872   pPageObj->SetDirty(true);
873   return true;
874 }
875 
876 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDFPageObj_GetStrokeWidth(FPDF_PAGEOBJECT page_object,float * width)877 FPDFPageObj_GetStrokeWidth(FPDF_PAGEOBJECT page_object, float* width) {
878   auto* pPageObj = CPDFPageObjectFromFPDFPageObject(page_object);
879   if (!pPageObj || !width)
880     return false;
881 
882   *width = pPageObj->m_GraphState.GetLineWidth();
883   return true;
884 }
885 
886 FPDF_EXPORT int FPDF_CALLCONV
FPDFPageObj_GetLineJoin(FPDF_PAGEOBJECT page_object)887 FPDFPageObj_GetLineJoin(FPDF_PAGEOBJECT page_object) {
888   auto* pPageObj = CPDFPageObjectFromFPDFPageObject(page_object);
889   return pPageObj ? static_cast<int>(pPageObj->m_GraphState.GetLineJoin()) : -1;
890 }
891 
892 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDFPageObj_SetLineJoin(FPDF_PAGEOBJECT page_object,int line_join)893 FPDFPageObj_SetLineJoin(FPDF_PAGEOBJECT page_object, int line_join) {
894   auto* pPageObj = CPDFPageObjectFromFPDFPageObject(page_object);
895   if (!pPageObj)
896     return false;
897 
898   if (line_join < FPDF_LINEJOIN_MITER || line_join > FPDF_LINEJOIN_BEVEL)
899     return false;
900 
901   pPageObj->m_GraphState.SetLineJoin(
902       static_cast<CFX_GraphStateData::LineJoin>(line_join));
903   pPageObj->SetDirty(true);
904   return true;
905 }
906 
907 FPDF_EXPORT int FPDF_CALLCONV
FPDFPageObj_GetLineCap(FPDF_PAGEOBJECT page_object)908 FPDFPageObj_GetLineCap(FPDF_PAGEOBJECT page_object) {
909   auto* pPageObj = CPDFPageObjectFromFPDFPageObject(page_object);
910   return pPageObj ? static_cast<int>(pPageObj->m_GraphState.GetLineCap()) : -1;
911 }
912 
913 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDFPageObj_SetLineCap(FPDF_PAGEOBJECT page_object,int line_cap)914 FPDFPageObj_SetLineCap(FPDF_PAGEOBJECT page_object, int line_cap) {
915   auto* pPageObj = CPDFPageObjectFromFPDFPageObject(page_object);
916   if (!pPageObj)
917     return false;
918 
919   if (line_cap < FPDF_LINECAP_BUTT ||
920       line_cap > FPDF_LINECAP_PROJECTING_SQUARE) {
921     return false;
922   }
923   pPageObj->m_GraphState.SetLineCap(
924       static_cast<CFX_GraphStateData::LineCap>(line_cap));
925   pPageObj->SetDirty(true);
926   return true;
927 }
928 
929 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDFPageObj_GetDashPhase(FPDF_PAGEOBJECT page_object,float * phase)930 FPDFPageObj_GetDashPhase(FPDF_PAGEOBJECT page_object, float* phase) {
931   auto* pPageObj = CPDFPageObjectFromFPDFPageObject(page_object);
932   if (!pPageObj || !phase)
933     return false;
934 
935   *phase = pPageObj->m_GraphState.GetLineDashPhase();
936   return true;
937 }
938 
939 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDFPageObj_SetDashPhase(FPDF_PAGEOBJECT page_object,float phase)940 FPDFPageObj_SetDashPhase(FPDF_PAGEOBJECT page_object, float phase) {
941   auto* pPageObj = CPDFPageObjectFromFPDFPageObject(page_object);
942   if (!pPageObj)
943     return false;
944 
945   pPageObj->m_GraphState.SetLineDashPhase(phase);
946   pPageObj->SetDirty(true);
947   return true;
948 }
949 
950 FPDF_EXPORT int FPDF_CALLCONV
FPDFPageObj_GetDashCount(FPDF_PAGEOBJECT page_object)951 FPDFPageObj_GetDashCount(FPDF_PAGEOBJECT page_object) {
952   auto* pPageObj = CPDFPageObjectFromFPDFPageObject(page_object);
953   return pPageObj ? pdfium::base::checked_cast<int>(
954                         pPageObj->m_GraphState.GetLineDashSize())
955                   : -1;
956 }
957 
958 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDFPageObj_GetDashArray(FPDF_PAGEOBJECT page_object,float * dash_array,size_t dash_count)959 FPDFPageObj_GetDashArray(FPDF_PAGEOBJECT page_object,
960                          float* dash_array,
961                          size_t dash_count) {
962   auto* pPageObj = CPDFPageObjectFromFPDFPageObject(page_object);
963   if (!pPageObj || !dash_array)
964     return false;
965 
966   auto dash_vector = pPageObj->m_GraphState.GetLineDashArray();
967   if (dash_vector.size() > dash_count)
968     return false;
969 
970   FXSYS_memcpy(dash_array, dash_vector.data(),
971                dash_vector.size() * sizeof(float));
972   return true;
973 }
974 
975 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDFPageObj_SetDashArray(FPDF_PAGEOBJECT page_object,const float * dash_array,size_t dash_count,float phase)976 FPDFPageObj_SetDashArray(FPDF_PAGEOBJECT page_object,
977                          const float* dash_array,
978                          size_t dash_count,
979                          float phase) {
980   if (dash_count > 0 && !dash_array)
981     return false;
982 
983   auto* pPageObj = CPDFPageObjectFromFPDFPageObject(page_object);
984   if (!pPageObj)
985     return false;
986 
987   std::vector<float> dashes;
988   if (dash_count > 0) {
989     dashes.reserve(dash_count);
990     dashes.assign(dash_array, dash_array + dash_count);
991   }
992 
993   pPageObj->m_GraphState.SetLineDash(dashes, phase, 1.0f);
994 
995   pPageObj->SetDirty(true);
996   return true;
997 }
998 
999 FPDF_EXPORT int FPDF_CALLCONV
FPDFFormObj_CountObjects(FPDF_PAGEOBJECT form_object)1000 FPDFFormObj_CountObjects(FPDF_PAGEOBJECT form_object) {
1001   const auto* pObjectList = CPDFPageObjHolderFromFPDFFormObject(form_object);
1002   return pObjectList ? pdfium::base::checked_cast<int>(
1003                            pObjectList->GetPageObjectCount())
1004                      : -1;
1005 }
1006 
1007 FPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV
FPDFFormObj_GetObject(FPDF_PAGEOBJECT form_object,unsigned long index)1008 FPDFFormObj_GetObject(FPDF_PAGEOBJECT form_object, unsigned long index) {
1009   const auto* pObjectList = CPDFPageObjHolderFromFPDFFormObject(form_object);
1010   if (!pObjectList)
1011     return nullptr;
1012 
1013   return FPDFPageObjectFromCPDFPageObject(
1014       pObjectList->GetPageObjectByIndex(index));
1015 }
1016