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(&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 
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