blob: 8e979e0212dda60c950a9e0af04180624905e27a [file] [log] [blame]
Haibo Huang49cc9302020-04-27 16:14:24 -07001// 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
46namespace {
47
48static_assert(FPDF_PAGEOBJ_TEXT == CPDF_PageObject::TEXT,
49 "FPDF_PAGEOBJ_TEXT/CPDF_PageObject::TEXT mismatch");
50static_assert(FPDF_PAGEOBJ_PATH == CPDF_PageObject::PATH,
51 "FPDF_PAGEOBJ_PATH/CPDF_PageObject::PATH mismatch");
52static_assert(FPDF_PAGEOBJ_IMAGE == CPDF_PageObject::IMAGE,
53 "FPDF_PAGEOBJ_IMAGE/CPDF_PageObject::IMAGE mismatch");
54static_assert(FPDF_PAGEOBJ_SHADING == CPDF_PageObject::SHADING,
55 "FPDF_PAGEOBJ_SHADING/CPDF_PageObject::SHADING mismatch");
56static_assert(FPDF_PAGEOBJ_FORM == CPDF_PageObject::FORM,
57 "FPDF_PAGEOBJ_FORM/CPDF_PageObject::FORM mismatch");
58
59bool 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
71void 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
103CPDF_Dictionary* GetMarkParamDict(FPDF_PAGEOBJECTMARK mark) {
104 CPDF_ContentMarkItem* pMarkItem =
105 CPDFContentMarkItemFromFPDFPageObjectMark(mark);
106 return pMarkItem ? pMarkItem->GetParam() : nullptr;
107}
108
109CPDF_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
132bool 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
139CPDF_FormObject* CPDFFormObjectFromFPDFPageObject(FPDF_PAGEOBJECT page_object) {
140 auto* pPageObj = CPDFPageObjectFromFPDFPageObject(page_object);
141 return pPageObj ? pPageObj->AsForm() : nullptr;
142}
143
144const 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
152FPDF_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(&currentTime) != -1) {
162 tm* pTM = FXSYS_localtime(&currentTime);
163 if (pTM) {
164 DateStr = ByteString::Format(
165 "D:%04d%02d%02d%02d%02d%02d", pTM->tm_year + 1900, pTM->tm_mon + 1,
166 pTM->tm_mday, pTM->tm_hour, pTM->tm_min, pTM->tm_sec);
167 }
168 }
169 }
170
171 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
186FPDF_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
201FPDF_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
234FPDF_EXPORT int FPDF_CALLCONV FPDFPage_GetRotation(FPDF_PAGE page) {
235 CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
236 return IsPageObject(pPage) ? pPage->GetPageRotation() : -1;
237}
238
239FPDF_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
255FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
256FPDFPage_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
268FPDF_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
276FPDF_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
285FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_HasTransparency(FPDF_PAGE page) {
286 CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
287 return pPage && pPage->BackgroundAlphaNeeded();
288}
289
290FPDF_EXPORT void FPDF_CALLCONV FPDFPageObj_Destroy(FPDF_PAGEOBJECT page_obj) {
291 delete CPDFPageObjectFromFPDFPageObject(page_obj);
292}
293
294FPDF_EXPORT int FPDF_CALLCONV
295FPDFPageObj_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
303FPDF_EXPORT FPDF_PAGEOBJECTMARK FPDF_CALLCONV
304FPDFPageObj_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
316FPDF_EXPORT FPDF_PAGEOBJECTMARK FPDF_CALLCONV
317FPDFPageObj_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
329FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
330FPDFPageObj_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
344FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
345FPDFPageObjMark_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
361FPDF_EXPORT int FPDF_CALLCONV
362FPDFPageObjMark_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
373FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
374FPDFPageObjMark_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
399FPDF_EXPORT FPDF_OBJECT_TYPE FPDF_CALLCONV
400FPDFPageObjMark_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
410FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
411FPDFPageObjMark_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
429FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
430FPDFPageObjMark_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
451FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
452FPDFPageObjMark_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
478FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
479FPDFPageObj_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
509FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
510FPDFPageObjMark_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
528FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
529FPDFPageObjMark_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
547FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
548FPDFPageObjMark_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
571FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
572FPDFPageObjMark_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
591FPDF_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
596FPDF_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
606FPDF_EXPORT void FPDF_CALLCONV
607FPDFPageObj_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
622FPDF_EXPORT void FPDF_CALLCONV
623FPDFPageObj_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
633FPDF_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
667FPDF_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
679FPDF_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
696FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
697FPDFPageObj_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
717FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
718FPDFPageObj_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
735FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
736FPDFPageObj_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
753FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
754FPDFPageObj_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
774FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
775FPDFPageObj_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
785FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
786FPDFPageObj_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
795FPDF_EXPORT int FPDF_CALLCONV
796FPDFPageObj_GetLineJoin(FPDF_PAGEOBJECT page_object) {
797 auto* pPageObj = CPDFPageObjectFromFPDFPageObject(page_object);
798 return pPageObj ? pPageObj->m_GraphState.GetLineJoin() : -1;
799}
800
801FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
802FPDFPageObj_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
820FPDF_EXPORT int FPDF_CALLCONV
821FPDFPageObj_GetLineCap(FPDF_PAGEOBJECT page_object) {
822 auto* pPageObj = CPDFPageObjectFromFPDFPageObject(page_object);
823 return pPageObj ? pPageObj->m_GraphState.GetLineCap() : -1;
824}
825
826FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
827FPDFPageObj_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
845FPDF_EXPORT int FPDF_CALLCONV
846FPDFFormObj_CountObjects(FPDF_PAGEOBJECT form_object) {
847 const auto* pObjectList = CPDFPageObjHolderFromFPDFFormObject(form_object);
848 return pObjectList ? pObjectList->GetPageObjectCount() : -1;
849}
850
851FPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV
852FPDFFormObj_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
861FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
862FPDFFormObj_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}