1 // Copyright 2014 PDFium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 // 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_pageobject.h"
23 #include "core/fpdfapi/page/cpdf_pathobject.h"
24 #include "core/fpdfapi/page/cpdf_shadingobject.h"
25 #include "core/fpdfapi/parser/cpdf_array.h"
26 #include "core/fpdfapi/parser/cpdf_dictionary.h"
27 #include "core/fpdfapi/parser/cpdf_document.h"
28 #include "core/fpdfapi/parser/cpdf_number.h"
29 #include "core/fpdfapi/parser/cpdf_string.h"
30 #include "core/fpdfapi/render/cpdf_docrenderdata.h"
31 #include "core/fpdfapi/render/cpdf_pagerendercache.h"
32 #include "core/fpdfdoc/cpdf_annot.h"
33 #include "core/fpdfdoc/cpdf_annotlist.h"
34 #include "core/fxcrt/fx_extension.h"
35 #include "fpdfsdk/cpdfsdk_helpers.h"
36 #include "public/fpdf_formfill.h"
37 #include "third_party/base/logging.h"
38 #include "third_party/base/ptr_util.h"
39 #include "third_party/base/stl_util.h"
40
41 #ifdef PDF_ENABLE_XFA
42 #include "fpdfsdk/fpdfxfa/cpdfxfa_context.h"
43 #include "fpdfsdk/fpdfxfa/cpdfxfa_page.h"
44 #endif // PDF_ENABLE_XFA
45
46 namespace {
47
48 static_assert(FPDF_PAGEOBJ_TEXT == CPDF_PageObject::TEXT,
49 "FPDF_PAGEOBJ_TEXT/CPDF_PageObject::TEXT mismatch");
50 static_assert(FPDF_PAGEOBJ_PATH == CPDF_PageObject::PATH,
51 "FPDF_PAGEOBJ_PATH/CPDF_PageObject::PATH mismatch");
52 static_assert(FPDF_PAGEOBJ_IMAGE == CPDF_PageObject::IMAGE,
53 "FPDF_PAGEOBJ_IMAGE/CPDF_PageObject::IMAGE mismatch");
54 static_assert(FPDF_PAGEOBJ_SHADING == CPDF_PageObject::SHADING,
55 "FPDF_PAGEOBJ_SHADING/CPDF_PageObject::SHADING mismatch");
56 static_assert(FPDF_PAGEOBJ_FORM == CPDF_PageObject::FORM,
57 "FPDF_PAGEOBJ_FORM/CPDF_PageObject::FORM mismatch");
58
IsPageObject(CPDF_Page * pPage)59 bool IsPageObject(CPDF_Page* pPage) {
60 if (!pPage)
61 return false;
62
63 const CPDF_Dictionary* pFormDict = pPage->GetDict();
64 if (!pFormDict->KeyExist("Type"))
65 return false;
66
67 const CPDF_Object* pObject = pFormDict->GetObjectFor("Type")->GetDirect();
68 return pObject && !pObject->GetString().Compare("Page");
69 }
70
CalcBoundingBox(CPDF_PageObject * pPageObj)71 void CalcBoundingBox(CPDF_PageObject* pPageObj) {
72 switch (pPageObj->GetType()) {
73 case CPDF_PageObject::TEXT: {
74 break;
75 }
76 case CPDF_PageObject::PATH: {
77 CPDF_PathObject* pPathObj = pPageObj->AsPath();
78 pPathObj->CalcBoundingBox();
79 break;
80 }
81 case CPDF_PageObject::IMAGE: {
82 CPDF_ImageObject* pImageObj = pPageObj->AsImage();
83 pImageObj->CalcBoundingBox();
84 break;
85 }
86 case CPDF_PageObject::SHADING: {
87 CPDF_ShadingObject* pShadingObj = pPageObj->AsShading();
88 pShadingObj->CalcBoundingBox();
89 break;
90 }
91 case CPDF_PageObject::FORM: {
92 CPDF_FormObject* pFormObj = pPageObj->AsForm();
93 pFormObj->CalcBoundingBox();
94 break;
95 }
96 default: {
97 NOTREACHED();
98 break;
99 }
100 }
101 }
102
GetMarkParamDict(FPDF_PAGEOBJECTMARK mark)103 CPDF_Dictionary* GetMarkParamDict(FPDF_PAGEOBJECTMARK mark) {
104 CPDF_ContentMarkItem* pMarkItem =
105 CPDFContentMarkItemFromFPDFPageObjectMark(mark);
106 return pMarkItem ? pMarkItem->GetParam() : nullptr;
107 }
108
GetOrCreateMarkParamsDict(FPDF_DOCUMENT document,FPDF_PAGEOBJECTMARK mark)109 CPDF_Dictionary* GetOrCreateMarkParamsDict(FPDF_DOCUMENT document,
110 FPDF_PAGEOBJECTMARK mark) {
111 CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
112 if (!pDoc)
113 return nullptr;
114
115 CPDF_ContentMarkItem* pMarkItem =
116 CPDFContentMarkItemFromFPDFPageObjectMark(mark);
117 if (!pMarkItem)
118 return nullptr;
119
120 CPDF_Dictionary* pParams = pMarkItem->GetParam();
121
122 // If the Params dict does not exist, create a new one.
123 if (!pParams) {
124 auto new_dict = pDoc->New<CPDF_Dictionary>();
125 pParams = new_dict.Get();
126 pMarkItem->SetDirectDict(std::move(new_dict));
127 }
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->m_ContentMarks.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 = pdfium::MakeUnique<CPDF_Document>(
154 pdfium::MakeUnique<CPDF_DocRenderData>(),
155 pdfium::MakeUnique<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 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 #ifdef PDF_ENABLE_XFA
179 pDoc->SetExtension(pdfium::MakeUnique<CPDFXFA_Context>(pDoc.get()));
180 #endif // PDF_ENABLE_XFA
181
182 // Caller takes ownership of pDoc.
183 return FPDFDocumentFromCPDFDocument(pDoc.release());
184 }
185
FPDFPage_Delete(FPDF_DOCUMENT document,int page_index)186 FPDF_EXPORT void FPDF_CALLCONV FPDFPage_Delete(FPDF_DOCUMENT document,
187 int page_index) {
188 auto* pDoc = CPDFDocumentFromFPDFDocument(document);
189 if (!pDoc)
190 return;
191
192 CPDF_Document::Extension* pExtension = pDoc->GetExtension();
193 if (pExtension) {
194 pExtension->DeletePage(page_index);
195 return;
196 }
197
198 pDoc->DeletePage(page_index);
199 }
200
FPDFPage_New(FPDF_DOCUMENT document,int page_index,double width,double height)201 FPDF_EXPORT FPDF_PAGE FPDF_CALLCONV FPDFPage_New(FPDF_DOCUMENT document,
202 int page_index,
203 double width,
204 double height) {
205 CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
206 if (!pDoc)
207 return nullptr;
208
209 page_index = pdfium::clamp(page_index, 0, pDoc->GetPageCount());
210 CPDF_Dictionary* pPageDict = pDoc->CreateNewPage(page_index);
211 if (!pPageDict)
212 return nullptr;
213
214 pPageDict->SetRectFor(pdfium::page_object::kMediaBox,
215 CFX_FloatRect(0, 0, width, height));
216 pPageDict->SetNewFor<CPDF_Number>(pdfium::page_object::kRotate, 0);
217 pPageDict->SetNewFor<CPDF_Dictionary>(pdfium::page_object::kResources);
218
219 #ifdef PDF_ENABLE_XFA
220 if (pDoc->GetExtension()) {
221 auto pXFAPage = pdfium::MakeRetain<CPDFXFA_Page>(pDoc, page_index);
222 pXFAPage->LoadPDFPageFromDict(pPageDict);
223 return FPDFPageFromIPDFPage(pXFAPage.Leak()); // Caller takes ownership.
224 }
225 #endif // PDF_ENABLE_XFA
226
227 auto pPage = pdfium::MakeRetain<CPDF_Page>(pDoc, pPageDict);
228 pPage->SetRenderCache(pdfium::MakeUnique<CPDF_PageRenderCache>(pPage.Get()));
229 pPage->ParseContent();
230
231 return FPDFPageFromIPDFPage(pPage.Leak()); // Caller takes ownership.
232 }
233
FPDFPage_GetRotation(FPDF_PAGE page)234 FPDF_EXPORT int FPDF_CALLCONV FPDFPage_GetRotation(FPDF_PAGE page) {
235 CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
236 return IsPageObject(pPage) ? pPage->GetPageRotation() : -1;
237 }
238
FPDFPage_InsertObject(FPDF_PAGE page,FPDF_PAGEOBJECT page_obj)239 FPDF_EXPORT void FPDF_CALLCONV FPDFPage_InsertObject(FPDF_PAGE page,
240 FPDF_PAGEOBJECT page_obj) {
241 CPDF_PageObject* pPageObj = CPDFPageObjectFromFPDFPageObject(page_obj);
242 if (!pPageObj)
243 return;
244
245 std::unique_ptr<CPDF_PageObject> pPageObjHolder(pPageObj);
246 CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
247 if (!IsPageObject(pPage))
248 return;
249
250 pPageObj->SetDirty(true);
251 pPage->AppendPageObject(std::move(pPageObjHolder));
252 CalcBoundingBox(pPageObj);
253 }
254
255 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDFPage_RemoveObject(FPDF_PAGE page,FPDF_PAGEOBJECT page_obj)256 FPDFPage_RemoveObject(FPDF_PAGE page, FPDF_PAGEOBJECT page_obj) {
257 CPDF_PageObject* pPageObj = CPDFPageObjectFromFPDFPageObject(page_obj);
258 if (!pPageObj)
259 return false;
260
261 CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
262 if (!IsPageObject(pPage))
263 return false;
264
265 return pPage->RemovePageObject(pPageObj);
266 }
267
FPDFPage_CountObjects(FPDF_PAGE page)268 FPDF_EXPORT int FPDF_CALLCONV FPDFPage_CountObjects(FPDF_PAGE page) {
269 CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
270 if (!IsPageObject(pPage))
271 return -1;
272
273 return pPage->GetPageObjectCount();
274 }
275
FPDFPage_GetObject(FPDF_PAGE page,int index)276 FPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV FPDFPage_GetObject(FPDF_PAGE page,
277 int index) {
278 CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
279 if (!IsPageObject(pPage))
280 return nullptr;
281
282 return FPDFPageObjectFromCPDFPageObject(pPage->GetPageObjectByIndex(index));
283 }
284
FPDFPage_HasTransparency(FPDF_PAGE page)285 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_HasTransparency(FPDF_PAGE page) {
286 CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
287 return pPage && pPage->BackgroundAlphaNeeded();
288 }
289
FPDFPageObj_Destroy(FPDF_PAGEOBJECT page_obj)290 FPDF_EXPORT void FPDF_CALLCONV FPDFPageObj_Destroy(FPDF_PAGEOBJECT page_obj) {
291 delete CPDFPageObjectFromFPDFPageObject(page_obj);
292 }
293
294 FPDF_EXPORT int FPDF_CALLCONV
FPDFPageObj_CountMarks(FPDF_PAGEOBJECT page_object)295 FPDFPageObj_CountMarks(FPDF_PAGEOBJECT page_object) {
296 CPDF_PageObject* pPageObj = CPDFPageObjectFromFPDFPageObject(page_object);
297 if (!pPageObj)
298 return -1;
299
300 return pPageObj->m_ContentMarks.CountItems();
301 }
302
303 FPDF_EXPORT FPDF_PAGEOBJECTMARK FPDF_CALLCONV
FPDFPageObj_GetMark(FPDF_PAGEOBJECT page_object,unsigned long index)304 FPDFPageObj_GetMark(FPDF_PAGEOBJECT page_object, unsigned long index) {
305 CPDF_PageObject* pPageObj = CPDFPageObjectFromFPDFPageObject(page_object);
306 if (!pPageObj)
307 return nullptr;
308
309 auto& mark = pPageObj->m_ContentMarks;
310 if (index >= mark.CountItems())
311 return nullptr;
312
313 return FPDFPageObjectMarkFromCPDFContentMarkItem(mark.GetItem(index));
314 }
315
316 FPDF_EXPORT FPDF_PAGEOBJECTMARK FPDF_CALLCONV
FPDFPageObj_AddMark(FPDF_PAGEOBJECT page_object,FPDF_BYTESTRING name)317 FPDFPageObj_AddMark(FPDF_PAGEOBJECT page_object, FPDF_BYTESTRING name) {
318 CPDF_PageObject* pPageObj = CPDFPageObjectFromFPDFPageObject(page_object);
319 if (!pPageObj)
320 return nullptr;
321
322 auto& mark = pPageObj->m_ContentMarks;
323 mark.AddMark(name);
324 unsigned long index = mark.CountItems() - 1;
325 pPageObj->SetDirty(true);
326 return FPDFPageObjectMarkFromCPDFContentMarkItem(mark.GetItem(index));
327 }
328
329 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDFPageObj_RemoveMark(FPDF_PAGEOBJECT page_object,FPDF_PAGEOBJECTMARK mark)330 FPDFPageObj_RemoveMark(FPDF_PAGEOBJECT page_object, FPDF_PAGEOBJECTMARK mark) {
331 CPDF_PageObject* pPageObj = CPDFPageObjectFromFPDFPageObject(page_object);
332 CPDF_ContentMarkItem* pMarkItem =
333 CPDFContentMarkItemFromFPDFPageObjectMark(mark);
334 if (!pPageObj || !pMarkItem)
335 return false;
336
337 bool result = pPageObj->m_ContentMarks.RemoveMark(pMarkItem);
338 if (result)
339 pPageObj->SetDirty(true);
340
341 return result;
342 }
343
344 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDFPageObjMark_GetName(FPDF_PAGEOBJECTMARK mark,void * buffer,unsigned long buflen,unsigned long * out_buflen)345 FPDFPageObjMark_GetName(FPDF_PAGEOBJECTMARK mark,
346 void* buffer,
347 unsigned long buflen,
348 unsigned long* out_buflen) {
349 if (!mark || !out_buflen)
350 return false;
351
352 const CPDF_ContentMarkItem* pMarkItem =
353 CPDFContentMarkItemFromFPDFPageObjectMark(mark);
354
355 *out_buflen = Utf16EncodeMaybeCopyAndReturnLength(
356 WideString::FromUTF8(pMarkItem->GetName().AsStringView()), buffer,
357 buflen);
358 return true;
359 }
360
361 FPDF_EXPORT int FPDF_CALLCONV
FPDFPageObjMark_CountParams(FPDF_PAGEOBJECTMARK mark)362 FPDFPageObjMark_CountParams(FPDF_PAGEOBJECTMARK mark) {
363 if (!mark)
364 return -1;
365
366 const CPDF_ContentMarkItem* pMarkItem =
367 CPDFContentMarkItemFromFPDFPageObjectMark(mark);
368
369 const CPDF_Dictionary* pParams = pMarkItem->GetParam();
370 return pParams ? pParams->size() : 0;
371 }
372
373 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDFPageObjMark_GetParamKey(FPDF_PAGEOBJECTMARK mark,unsigned long index,void * buffer,unsigned long buflen,unsigned long * out_buflen)374 FPDFPageObjMark_GetParamKey(FPDF_PAGEOBJECTMARK mark,
375 unsigned long index,
376 void* buffer,
377 unsigned long buflen,
378 unsigned long* out_buflen) {
379 if (!out_buflen)
380 return false;
381
382 const CPDF_Dictionary* pParams = GetMarkParamDict(mark);
383 if (!pParams)
384 return false;
385
386 CPDF_DictionaryLocker locker(pParams);
387 for (auto& it : locker) {
388 if (index == 0) {
389 *out_buflen = Utf16EncodeMaybeCopyAndReturnLength(
390 WideString::FromUTF8(it.first.AsStringView()), buffer, buflen);
391 return true;
392 }
393 --index;
394 }
395
396 return false;
397 }
398
399 FPDF_EXPORT FPDF_OBJECT_TYPE FPDF_CALLCONV
FPDFPageObjMark_GetParamValueType(FPDF_PAGEOBJECTMARK mark,FPDF_BYTESTRING key)400 FPDFPageObjMark_GetParamValueType(FPDF_PAGEOBJECTMARK mark,
401 FPDF_BYTESTRING key) {
402 const CPDF_Dictionary* pParams = GetMarkParamDict(mark);
403 if (!pParams)
404 return FPDF_OBJECT_UNKNOWN;
405
406 const CPDF_Object* pObject = pParams->GetObjectFor(key);
407 return pObject ? pObject->GetType() : FPDF_OBJECT_UNKNOWN;
408 }
409
410 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDFPageObjMark_GetParamIntValue(FPDF_PAGEOBJECTMARK mark,FPDF_BYTESTRING key,int * out_value)411 FPDFPageObjMark_GetParamIntValue(FPDF_PAGEOBJECTMARK mark,
412 FPDF_BYTESTRING key,
413 int* out_value) {
414 if (!out_value)
415 return false;
416
417 const CPDF_Dictionary* pParams = GetMarkParamDict(mark);
418 if (!pParams)
419 return false;
420
421 const CPDF_Object* pObj = pParams->GetObjectFor(key);
422 if (!pObj || !pObj->IsNumber())
423 return false;
424
425 *out_value = pObj->GetInteger();
426 return true;
427 }
428
429 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDFPageObjMark_GetParamStringValue(FPDF_PAGEOBJECTMARK mark,FPDF_BYTESTRING key,void * buffer,unsigned long buflen,unsigned long * out_buflen)430 FPDFPageObjMark_GetParamStringValue(FPDF_PAGEOBJECTMARK mark,
431 FPDF_BYTESTRING key,
432 void* buffer,
433 unsigned long buflen,
434 unsigned long* out_buflen) {
435 if (!out_buflen)
436 return false;
437
438 const CPDF_Dictionary* pParams = GetMarkParamDict(mark);
439 if (!pParams)
440 return false;
441
442 const CPDF_Object* pObj = pParams->GetObjectFor(key);
443 if (!pObj || !pObj->IsString())
444 return false;
445
446 *out_buflen = Utf16EncodeMaybeCopyAndReturnLength(
447 WideString::FromUTF8(pObj->GetString().AsStringView()), buffer, buflen);
448 return true;
449 }
450
451 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDFPageObjMark_GetParamBlobValue(FPDF_PAGEOBJECTMARK mark,FPDF_BYTESTRING key,void * buffer,unsigned long buflen,unsigned long * out_buflen)452 FPDFPageObjMark_GetParamBlobValue(FPDF_PAGEOBJECTMARK mark,
453 FPDF_BYTESTRING key,
454 void* buffer,
455 unsigned long buflen,
456 unsigned long* out_buflen) {
457 if (!out_buflen)
458 return false;
459
460 const CPDF_Dictionary* pParams = GetMarkParamDict(mark);
461 if (!pParams)
462 return false;
463
464 const CPDF_Object* pObj = pParams->GetObjectFor(key);
465 if (!pObj || !pObj->IsString())
466 return false;
467
468 ByteString result = pObj->GetString();
469 unsigned long len = result.GetLength();
470
471 if (buffer && len <= buflen)
472 memcpy(buffer, result.c_str(), len);
473
474 *out_buflen = len;
475 return true;
476 }
477
478 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDFPageObj_HasTransparency(FPDF_PAGEOBJECT page_object)479 FPDFPageObj_HasTransparency(FPDF_PAGEOBJECT page_object) {
480 CPDF_PageObject* pPageObj = CPDFPageObjectFromFPDFPageObject(page_object);
481 if (!pPageObj)
482 return false;
483
484 if (pPageObj->m_GeneralState.GetBlendType() != BlendMode::kNormal)
485 return true;
486
487 const CPDF_Dictionary* pSMaskDict =
488 ToDictionary(pPageObj->m_GeneralState.GetSoftMask());
489 if (pSMaskDict)
490 return true;
491
492 if (pPageObj->m_GeneralState.GetFillAlpha() != 1.0f)
493 return true;
494
495 if (pPageObj->IsPath() && pPageObj->m_GeneralState.GetStrokeAlpha() != 1.0f)
496 return true;
497
498 if (!pPageObj->IsForm())
499 return false;
500
501 const CPDF_Form* pForm = pPageObj->AsForm()->form();
502 if (!pForm)
503 return false;
504
505 const CPDF_Transparency& trans = pForm->GetTransparency();
506 return trans.IsGroup() || trans.IsIsolated();
507 }
508
509 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDFPageObjMark_SetIntParam(FPDF_DOCUMENT document,FPDF_PAGEOBJECT page_object,FPDF_PAGEOBJECTMARK mark,FPDF_BYTESTRING key,int value)510 FPDFPageObjMark_SetIntParam(FPDF_DOCUMENT document,
511 FPDF_PAGEOBJECT page_object,
512 FPDF_PAGEOBJECTMARK mark,
513 FPDF_BYTESTRING key,
514 int value) {
515 CPDF_PageObject* pPageObj = CPDFPageObjectFromFPDFPageObject(page_object);
516 if (!pPageObj || !PageObjectContainsMark(pPageObj, mark))
517 return false;
518
519 CPDF_Dictionary* pParams = GetOrCreateMarkParamsDict(document, mark);
520 if (!pParams)
521 return false;
522
523 pParams->SetNewFor<CPDF_Number>(key, value);
524 pPageObj->SetDirty(true);
525 return true;
526 }
527
528 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDFPageObjMark_SetStringParam(FPDF_DOCUMENT document,FPDF_PAGEOBJECT page_object,FPDF_PAGEOBJECTMARK mark,FPDF_BYTESTRING key,FPDF_BYTESTRING value)529 FPDFPageObjMark_SetStringParam(FPDF_DOCUMENT document,
530 FPDF_PAGEOBJECT page_object,
531 FPDF_PAGEOBJECTMARK mark,
532 FPDF_BYTESTRING key,
533 FPDF_BYTESTRING value) {
534 CPDF_PageObject* pPageObj = CPDFPageObjectFromFPDFPageObject(page_object);
535 if (!pPageObj || !PageObjectContainsMark(pPageObj, mark))
536 return false;
537
538 CPDF_Dictionary* pParams = GetOrCreateMarkParamsDict(document, mark);
539 if (!pParams)
540 return false;
541
542 pParams->SetNewFor<CPDF_String>(key, value, false);
543 pPageObj->SetDirty(true);
544 return true;
545 }
546
547 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)548 FPDFPageObjMark_SetBlobParam(FPDF_DOCUMENT document,
549 FPDF_PAGEOBJECT page_object,
550 FPDF_PAGEOBJECTMARK mark,
551 FPDF_BYTESTRING key,
552 void* value,
553 unsigned long value_len) {
554 CPDF_PageObject* pPageObj = CPDFPageObjectFromFPDFPageObject(page_object);
555 if (!pPageObj || !PageObjectContainsMark(pPageObj, mark))
556 return false;
557
558 CPDF_Dictionary* pParams = GetOrCreateMarkParamsDict(document, mark);
559 if (!pParams)
560 return false;
561
562 if (!value && value_len > 0)
563 return false;
564
565 pParams->SetNewFor<CPDF_String>(
566 key, ByteString(static_cast<const char*>(value), value_len), true);
567 pPageObj->SetDirty(true);
568 return true;
569 }
570
571 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDFPageObjMark_RemoveParam(FPDF_PAGEOBJECT page_object,FPDF_PAGEOBJECTMARK mark,FPDF_BYTESTRING key)572 FPDFPageObjMark_RemoveParam(FPDF_PAGEOBJECT page_object,
573 FPDF_PAGEOBJECTMARK mark,
574 FPDF_BYTESTRING key) {
575 CPDF_PageObject* pPageObj = CPDFPageObjectFromFPDFPageObject(page_object);
576 if (!pPageObj)
577 return false;
578
579 CPDF_Dictionary* pParams = GetMarkParamDict(mark);
580 if (!pParams)
581 return false;
582
583 auto removed = pParams->RemoveFor(key);
584 if (!removed)
585 return false;
586
587 pPageObj->SetDirty(true);
588 return true;
589 }
590
FPDFPageObj_GetType(FPDF_PAGEOBJECT page_object)591 FPDF_EXPORT int FPDF_CALLCONV FPDFPageObj_GetType(FPDF_PAGEOBJECT page_object) {
592 CPDF_PageObject* pPageObj = CPDFPageObjectFromFPDFPageObject(page_object);
593 return pPageObj ? pPageObj->GetType() : 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 void FPDF_CALLCONV
FPDFPageObj_SetBlendMode(FPDF_PAGEOBJECT page_object,FPDF_BYTESTRING blend_mode)623 FPDFPageObj_SetBlendMode(FPDF_PAGEOBJECT page_object,
624 FPDF_BYTESTRING blend_mode) {
625 CPDF_PageObject* pPageObj = CPDFPageObjectFromFPDFPageObject(page_object);
626 if (!pPageObj)
627 return;
628
629 pPageObj->m_GeneralState.SetBlendMode(blend_mode);
630 pPageObj->SetDirty(true);
631 }
632
FPDFPage_TransformAnnots(FPDF_PAGE page,double a,double b,double c,double d,double e,double f)633 FPDF_EXPORT void FPDF_CALLCONV FPDFPage_TransformAnnots(FPDF_PAGE page,
634 double a,
635 double b,
636 double c,
637 double d,
638 double e,
639 double f) {
640 CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
641 if (!pPage)
642 return;
643
644 CPDF_AnnotList AnnotList(pPage);
645 for (size_t i = 0; i < AnnotList.Count(); ++i) {
646 CPDF_Annot* pAnnot = AnnotList.GetAt(i);
647 CFX_Matrix matrix((float)a, (float)b, (float)c, (float)d, (float)e,
648 (float)f);
649 CFX_FloatRect rect = matrix.TransformRect(pAnnot->GetRect());
650
651 CPDF_Dictionary* pAnnotDict = pAnnot->GetAnnotDict();
652 CPDF_Array* pRectArray = pAnnotDict->GetArrayFor("Rect");
653 if (pRectArray)
654 pRectArray->Clear();
655 else
656 pRectArray = pAnnotDict->SetNewFor<CPDF_Array>("Rect");
657
658 pRectArray->AddNew<CPDF_Number>(rect.left);
659 pRectArray->AddNew<CPDF_Number>(rect.bottom);
660 pRectArray->AddNew<CPDF_Number>(rect.right);
661 pRectArray->AddNew<CPDF_Number>(rect.top);
662
663 // TODO(unknown): Transform AP's rectangle
664 }
665 }
666
FPDFPage_SetRotation(FPDF_PAGE page,int rotate)667 FPDF_EXPORT void FPDF_CALLCONV FPDFPage_SetRotation(FPDF_PAGE page,
668 int rotate) {
669 CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
670 if (!IsPageObject(pPage))
671 return;
672
673 rotate %= 4;
674 pPage->GetDict()->SetNewFor<CPDF_Number>(pdfium::page_object::kRotate,
675 rotate * 90);
676 pPage->UpdateDimensions();
677 }
678
FPDFPageObj_SetFillColor(FPDF_PAGEOBJECT page_object,unsigned int R,unsigned int G,unsigned int B,unsigned int A)679 FPDF_BOOL FPDFPageObj_SetFillColor(FPDF_PAGEOBJECT page_object,
680 unsigned int R,
681 unsigned int G,
682 unsigned int B,
683 unsigned int A) {
684 CPDF_PageObject* pPageObj = CPDFPageObjectFromFPDFPageObject(page_object);
685 if (!pPageObj || R > 255 || G > 255 || B > 255 || A > 255)
686 return false;
687
688 std::vector<float> rgb = {R / 255.f, G / 255.f, B / 255.f};
689 pPageObj->m_GeneralState.SetFillAlpha(A / 255.f);
690 pPageObj->m_ColorState.SetFillColor(
691 CPDF_ColorSpace::GetStockCS(PDFCS_DEVICERGB), rgb);
692 pPageObj->SetDirty(true);
693 return true;
694 }
695
696 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDFPageObj_GetFillColor(FPDF_PAGEOBJECT page_object,unsigned int * R,unsigned int * G,unsigned int * B,unsigned int * A)697 FPDFPageObj_GetFillColor(FPDF_PAGEOBJECT page_object,
698 unsigned int* R,
699 unsigned int* G,
700 unsigned int* B,
701 unsigned int* A) {
702 auto* pPageObj = CPDFPageObjectFromFPDFPageObject(page_object);
703 if (!pPageObj || !R || !G || !B || !A)
704 return false;
705
706 if (!pPageObj->m_ColorState.HasRef())
707 return false;
708
709 FX_COLORREF fill_color = pPageObj->m_ColorState.GetFillColorRef();
710 *R = FXSYS_GetRValue(fill_color);
711 *G = FXSYS_GetGValue(fill_color);
712 *B = FXSYS_GetBValue(fill_color);
713 *A = FXSYS_GetUnsignedAlpha(pPageObj->m_GeneralState.GetFillAlpha());
714 return true;
715 }
716
717 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDFPageObj_GetBounds(FPDF_PAGEOBJECT page_object,float * left,float * bottom,float * right,float * top)718 FPDFPageObj_GetBounds(FPDF_PAGEOBJECT page_object,
719 float* left,
720 float* bottom,
721 float* right,
722 float* top) {
723 CPDF_PageObject* pPageObj = CPDFPageObjectFromFPDFPageObject(page_object);
724 if (!pPageObj)
725 return false;
726
727 const CFX_FloatRect& bbox = pPageObj->GetRect();
728 *left = bbox.left;
729 *bottom = bbox.bottom;
730 *right = bbox.right;
731 *top = bbox.top;
732 return true;
733 }
734
735 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDFPageObj_SetStrokeColor(FPDF_PAGEOBJECT page_object,unsigned int R,unsigned int G,unsigned int B,unsigned int A)736 FPDFPageObj_SetStrokeColor(FPDF_PAGEOBJECT page_object,
737 unsigned int R,
738 unsigned int G,
739 unsigned int B,
740 unsigned int A) {
741 auto* pPageObj = CPDFPageObjectFromFPDFPageObject(page_object);
742 if (!pPageObj || R > 255 || G > 255 || B > 255 || A > 255)
743 return false;
744
745 std::vector<float> rgb = {R / 255.f, G / 255.f, B / 255.f};
746 pPageObj->m_GeneralState.SetStrokeAlpha(A / 255.f);
747 pPageObj->m_ColorState.SetStrokeColor(
748 CPDF_ColorSpace::GetStockCS(PDFCS_DEVICERGB), rgb);
749 pPageObj->SetDirty(true);
750 return true;
751 }
752
753 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDFPageObj_GetStrokeColor(FPDF_PAGEOBJECT page_object,unsigned int * R,unsigned int * G,unsigned int * B,unsigned int * A)754 FPDFPageObj_GetStrokeColor(FPDF_PAGEOBJECT page_object,
755 unsigned int* R,
756 unsigned int* G,
757 unsigned int* B,
758 unsigned int* A) {
759 auto* pPageObj = CPDFPageObjectFromFPDFPageObject(page_object);
760 if (!pPageObj || !R || !G || !B || !A)
761 return false;
762
763 if (!pPageObj->m_ColorState.HasRef())
764 return false;
765
766 FX_COLORREF stroke_color = pPageObj->m_ColorState.GetStrokeColorRef();
767 *R = FXSYS_GetRValue(stroke_color);
768 *G = FXSYS_GetGValue(stroke_color);
769 *B = FXSYS_GetBValue(stroke_color);
770 *A = FXSYS_GetUnsignedAlpha(pPageObj->m_GeneralState.GetStrokeAlpha());
771 return true;
772 }
773
774 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDFPageObj_SetStrokeWidth(FPDF_PAGEOBJECT page_object,float width)775 FPDFPageObj_SetStrokeWidth(FPDF_PAGEOBJECT page_object, float width) {
776 auto* pPageObj = CPDFPageObjectFromFPDFPageObject(page_object);
777 if (!pPageObj || width < 0.0f)
778 return false;
779
780 pPageObj->m_GraphState.SetLineWidth(width);
781 pPageObj->SetDirty(true);
782 return true;
783 }
784
785 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDFPageObj_GetStrokeWidth(FPDF_PAGEOBJECT page_object,float * width)786 FPDFPageObj_GetStrokeWidth(FPDF_PAGEOBJECT page_object, float* width) {
787 auto* pPageObj = CPDFPageObjectFromFPDFPageObject(page_object);
788 if (!pPageObj || !width)
789 return false;
790
791 *width = pPageObj->m_GraphState.GetLineWidth();
792 return true;
793 }
794
795 FPDF_EXPORT int FPDF_CALLCONV
FPDFPageObj_GetLineJoin(FPDF_PAGEOBJECT page_object)796 FPDFPageObj_GetLineJoin(FPDF_PAGEOBJECT page_object) {
797 auto* pPageObj = CPDFPageObjectFromFPDFPageObject(page_object);
798 return pPageObj ? pPageObj->m_GraphState.GetLineJoin() : -1;
799 }
800
801 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDFPageObj_SetLineJoin(FPDF_PAGEOBJECT page_object,int line_join)802 FPDFPageObj_SetLineJoin(FPDF_PAGEOBJECT page_object, int line_join) {
803 auto* pPageObj = CPDFPageObjectFromFPDFPageObject(page_object);
804 if (!pPageObj)
805 return false;
806
807 constexpr int kLineJoinMiter =
808 static_cast<int>(CFX_GraphStateData::LineJoin::LineJoinMiter);
809 constexpr int kLineJoinBevel =
810 static_cast<int>(CFX_GraphStateData::LineJoin::LineJoinBevel);
811 if (line_join < kLineJoinMiter || line_join > kLineJoinBevel)
812 return false;
813
814 pPageObj->m_GraphState.SetLineJoin(
815 static_cast<CFX_GraphStateData::LineJoin>(line_join));
816 pPageObj->SetDirty(true);
817 return true;
818 }
819
820 FPDF_EXPORT int FPDF_CALLCONV
FPDFPageObj_GetLineCap(FPDF_PAGEOBJECT page_object)821 FPDFPageObj_GetLineCap(FPDF_PAGEOBJECT page_object) {
822 auto* pPageObj = CPDFPageObjectFromFPDFPageObject(page_object);
823 return pPageObj ? pPageObj->m_GraphState.GetLineCap() : -1;
824 }
825
826 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDFPageObj_SetLineCap(FPDF_PAGEOBJECT page_object,int line_cap)827 FPDFPageObj_SetLineCap(FPDF_PAGEOBJECT page_object, int line_cap) {
828 auto* pPageObj = CPDFPageObjectFromFPDFPageObject(page_object);
829 if (!pPageObj)
830 return false;
831
832 constexpr int kLineCapButt =
833 static_cast<int>(CFX_GraphStateData::LineCap::LineCapButt);
834 constexpr int kLineCapSquare =
835 static_cast<int>(CFX_GraphStateData::LineCap::LineCapSquare);
836 if (line_cap < kLineCapButt || line_cap > kLineCapSquare)
837 return false;
838
839 pPageObj->m_GraphState.SetLineCap(
840 static_cast<CFX_GraphStateData::LineCap>(line_cap));
841 pPageObj->SetDirty(true);
842 return true;
843 }
844
845 FPDF_EXPORT int FPDF_CALLCONV
FPDFFormObj_CountObjects(FPDF_PAGEOBJECT form_object)846 FPDFFormObj_CountObjects(FPDF_PAGEOBJECT form_object) {
847 const auto* pObjectList = CPDFPageObjHolderFromFPDFFormObject(form_object);
848 return pObjectList ? pObjectList->GetPageObjectCount() : -1;
849 }
850
851 FPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV
FPDFFormObj_GetObject(FPDF_PAGEOBJECT form_object,unsigned long index)852 FPDFFormObj_GetObject(FPDF_PAGEOBJECT form_object, unsigned long index) {
853 const auto* pObjectList = CPDFPageObjHolderFromFPDFFormObject(form_object);
854 if (!pObjectList)
855 return nullptr;
856
857 return FPDFPageObjectFromCPDFPageObject(
858 pObjectList->GetPageObjectByIndex(index));
859 }
860
861 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDFFormObj_GetMatrix(FPDF_PAGEOBJECT form_object,FS_MATRIX * matrix)862 FPDFFormObj_GetMatrix(FPDF_PAGEOBJECT form_object, FS_MATRIX* matrix) {
863 CPDF_FormObject* pFormObj = CPDFFormObjectFromFPDFPageObject(form_object);
864 if (!pFormObj || !matrix)
865 return false;
866
867 *matrix = FSMatrixFromCFXMatrix(pFormObj->form_matrix());
868 return true;
869 }
870