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