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(¤tTime) != -1) {
162 tm* pTM = FXSYS_localtime(¤tTime);
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