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
13 #include "core/fpdfapi/edit/cpdf_pagecontentgenerator.h"
14 #include "core/fpdfapi/page/cpdf_form.h"
15 #include "core/fpdfapi/page/cpdf_formobject.h"
16 #include "core/fpdfapi/page/cpdf_imageobject.h"
17 #include "core/fpdfapi/page/cpdf_page.h"
18 #include "core/fpdfapi/page/cpdf_pageobject.h"
19 #include "core/fpdfapi/page/cpdf_pathobject.h"
20 #include "core/fpdfapi/page/cpdf_shadingobject.h"
21 #include "core/fpdfapi/parser/cpdf_array.h"
22 #include "core/fpdfapi/parser/cpdf_document.h"
23 #include "core/fpdfapi/parser/cpdf_number.h"
24 #include "core/fpdfapi/parser/cpdf_string.h"
25 #include "core/fpdfdoc/cpdf_annot.h"
26 #include "core/fpdfdoc/cpdf_annotlist.h"
27 #include "fpdfsdk/fsdk_define.h"
28 #include "public/fpdf_formfill.h"
29 #include "third_party/base/logging.h"
30 #include "third_party/base/stl_util.h"
31
32 #ifdef PDF_ENABLE_XFA
33 #include "fpdfsdk/fpdfxfa/cpdfxfa_context.h"
34 #include "fpdfsdk/fpdfxfa/cpdfxfa_page.h"
35 #endif // PDF_ENABLE_XFA
36
37 #if _FX_OS_ == _FX_OS_ANDROID_
38 #include <time.h>
39 #else
40 #include <ctime>
41 #endif
42
43 namespace {
44
45 static_assert(FPDF_PAGEOBJ_TEXT == CPDF_PageObject::TEXT,
46 "FPDF_PAGEOBJ_TEXT/CPDF_PageObject::TEXT mismatch");
47 static_assert(FPDF_PAGEOBJ_PATH == CPDF_PageObject::PATH,
48 "FPDF_PAGEOBJ_PATH/CPDF_PageObject::PATH mismatch");
49 static_assert(FPDF_PAGEOBJ_IMAGE == CPDF_PageObject::IMAGE,
50 "FPDF_PAGEOBJ_IMAGE/CPDF_PageObject::IMAGE mismatch");
51 static_assert(FPDF_PAGEOBJ_SHADING == CPDF_PageObject::SHADING,
52 "FPDF_PAGEOBJ_SHADING/CPDF_PageObject::SHADING mismatch");
53 static_assert(FPDF_PAGEOBJ_FORM == CPDF_PageObject::FORM,
54 "FPDF_PAGEOBJ_FORM/CPDF_PageObject::FORM mismatch");
55
IsPageObject(CPDF_Page * pPage)56 bool IsPageObject(CPDF_Page* pPage) {
57 if (!pPage || !pPage->m_pFormDict || !pPage->m_pFormDict->KeyExist("Type"))
58 return false;
59
60 CPDF_Object* pObject = pPage->m_pFormDict->GetObjectFor("Type")->GetDirect();
61 return pObject && !pObject->GetString().Compare("Page");
62 }
63
CalcBoundingBox(CPDF_PageObject * pPageObj)64 void CalcBoundingBox(CPDF_PageObject* pPageObj) {
65 switch (pPageObj->GetType()) {
66 case CPDF_PageObject::TEXT: {
67 break;
68 }
69 case CPDF_PageObject::PATH: {
70 CPDF_PathObject* pPathObj = pPageObj->AsPath();
71 pPathObj->CalcBoundingBox();
72 break;
73 }
74 case CPDF_PageObject::IMAGE: {
75 CPDF_ImageObject* pImageObj = pPageObj->AsImage();
76 pImageObj->CalcBoundingBox();
77 break;
78 }
79 case CPDF_PageObject::SHADING: {
80 CPDF_ShadingObject* pShadingObj = pPageObj->AsShading();
81 pShadingObj->CalcBoundingBox();
82 break;
83 }
84 case CPDF_PageObject::FORM: {
85 CPDF_FormObject* pFormObj = pPageObj->AsForm();
86 pFormObj->CalcBoundingBox();
87 break;
88 }
89 default: {
90 NOTREACHED();
91 break;
92 }
93 }
94 }
95
96 } // namespace
97
FPDF_CreateNewDocument()98 FPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV FPDF_CreateNewDocument() {
99 auto pDoc = pdfium::MakeUnique<CPDF_Document>(nullptr);
100 pDoc->CreateNewDoc();
101
102 time_t currentTime;
103 ByteString DateStr;
104 if (FSDK_IsSandBoxPolicyEnabled(FPDF_POLICY_MACHINETIME_ACCESS)) {
105 if (time(¤tTime) != -1) {
106 tm* pTM = localtime(¤tTime);
107 if (pTM) {
108 DateStr = ByteString::Format(
109 "D:%04d%02d%02d%02d%02d%02d", pTM->tm_year + 1900, pTM->tm_mon + 1,
110 pTM->tm_mday, pTM->tm_hour, pTM->tm_min, pTM->tm_sec);
111 }
112 }
113 }
114
115 CPDF_Dictionary* pInfoDict = pDoc->GetInfo();
116 if (pInfoDict) {
117 if (FSDK_IsSandBoxPolicyEnabled(FPDF_POLICY_MACHINETIME_ACCESS))
118 pInfoDict->SetNewFor<CPDF_String>("CreationDate", DateStr, false);
119 pInfoDict->SetNewFor<CPDF_String>("Creator", L"PDFium");
120 }
121
122 // Caller takes ownership of pDoc.
123 return FPDFDocumentFromCPDFDocument(pDoc.release());
124 }
125
FPDFPage_Delete(FPDF_DOCUMENT document,int page_index)126 FPDF_EXPORT void FPDF_CALLCONV FPDFPage_Delete(FPDF_DOCUMENT document,
127 int page_index) {
128 if (UnderlyingDocumentType* pDoc = UnderlyingFromFPDFDocument(document))
129 pDoc->DeletePage(page_index);
130 }
131
FPDFPage_New(FPDF_DOCUMENT document,int page_index,double width,double height)132 FPDF_EXPORT FPDF_PAGE FPDF_CALLCONV FPDFPage_New(FPDF_DOCUMENT document,
133 int page_index,
134 double width,
135 double height) {
136 CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
137 if (!pDoc)
138 return nullptr;
139
140 page_index = pdfium::clamp(page_index, 0, pDoc->GetPageCount());
141 CPDF_Dictionary* pPageDict = pDoc->CreateNewPage(page_index);
142 if (!pPageDict)
143 return nullptr;
144
145 CPDF_Array* pMediaBoxArray = pPageDict->SetNewFor<CPDF_Array>("MediaBox");
146 pMediaBoxArray->AddNew<CPDF_Number>(0);
147 pMediaBoxArray->AddNew<CPDF_Number>(0);
148 pMediaBoxArray->AddNew<CPDF_Number>(static_cast<float>(width));
149 pMediaBoxArray->AddNew<CPDF_Number>(static_cast<float>(height));
150 pPageDict->SetNewFor<CPDF_Number>("Rotate", 0);
151 pPageDict->SetNewFor<CPDF_Dictionary>("Resources");
152
153 #ifdef PDF_ENABLE_XFA
154 auto pXFAPage = pdfium::MakeRetain<CPDFXFA_Page>(
155 static_cast<CPDFXFA_Context*>(document), page_index);
156 pXFAPage->LoadPDFPage(pPageDict);
157 return pXFAPage.Leak(); // Caller takes ownership.
158 #else // PDF_ENABLE_XFA
159 auto pPage = pdfium::MakeUnique<CPDF_Page>(pDoc, pPageDict, true);
160 pPage->ParseContent();
161 return pPage.release(); // Caller takes ownership.
162 #endif // PDF_ENABLE_XFA
163 }
164
FPDFPage_GetRotation(FPDF_PAGE page)165 FPDF_EXPORT int FPDF_CALLCONV FPDFPage_GetRotation(FPDF_PAGE page) {
166 CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
167 return IsPageObject(pPage) ? pPage->GetPageRotation() : -1;
168 }
169
FPDFPage_InsertObject(FPDF_PAGE page,FPDF_PAGEOBJECT page_obj)170 FPDF_EXPORT void FPDF_CALLCONV FPDFPage_InsertObject(FPDF_PAGE page,
171 FPDF_PAGEOBJECT page_obj) {
172 CPDF_PageObject* pPageObj = CPDFPageObjectFromFPDFPageObject(page_obj);
173 if (!pPageObj)
174 return;
175
176 std::unique_ptr<CPDF_PageObject> pPageObjHolder(pPageObj);
177 CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
178 if (!IsPageObject(pPage))
179 return;
180 pPageObj->SetDirty(true);
181 pPage->GetPageObjectList()->push_back(std::move(pPageObjHolder));
182 CalcBoundingBox(pPageObj);
183 }
184
FPDFPage_CountObject(FPDF_PAGE page)185 FPDF_EXPORT int FPDF_CALLCONV FPDFPage_CountObject(FPDF_PAGE page) {
186 return FPDFPage_CountObjects(page);
187 }
188
FPDFPage_CountObjects(FPDF_PAGE page)189 FPDF_EXPORT int FPDF_CALLCONV FPDFPage_CountObjects(FPDF_PAGE page) {
190 CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
191 if (!IsPageObject(pPage))
192 return -1;
193 return pdfium::CollectionSize<int>(*pPage->GetPageObjectList());
194 }
195
FPDFPage_GetObject(FPDF_PAGE page,int index)196 FPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV FPDFPage_GetObject(FPDF_PAGE page,
197 int index) {
198 CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
199 if (!IsPageObject(pPage))
200 return nullptr;
201 return pPage->GetPageObjectList()->GetPageObjectByIndex(index);
202 }
203
FPDFPage_HasTransparency(FPDF_PAGE page)204 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_HasTransparency(FPDF_PAGE page) {
205 CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
206 return pPage && pPage->BackgroundAlphaNeeded();
207 }
208
FPDFPageObj_Destroy(FPDF_PAGEOBJECT page_obj)209 FPDF_EXPORT void FPDF_CALLCONV FPDFPageObj_Destroy(FPDF_PAGEOBJECT page_obj) {
210 delete CPDFPageObjectFromFPDFPageObject(page_obj);
211 }
212
213 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDFPageObj_HasTransparency(FPDF_PAGEOBJECT pageObject)214 FPDFPageObj_HasTransparency(FPDF_PAGEOBJECT pageObject) {
215 if (!pageObject)
216 return false;
217
218 CPDF_PageObject* pPageObj = CPDFPageObjectFromFPDFPageObject(pageObject);
219 int blend_type = pPageObj->m_GeneralState.GetBlendType();
220 if (blend_type != FXDIB_BLEND_NORMAL)
221 return true;
222
223 CPDF_Dictionary* pSMaskDict =
224 ToDictionary(pPageObj->m_GeneralState.GetSoftMask());
225 if (pSMaskDict)
226 return true;
227
228 if (pPageObj->m_GeneralState.GetFillAlpha() != 1.0f)
229 return true;
230
231 if (pPageObj->IsPath() && pPageObj->m_GeneralState.GetStrokeAlpha() != 1.0f) {
232 return true;
233 }
234
235 if (pPageObj->IsForm()) {
236 const CPDF_Form* pForm = pPageObj->AsForm()->form();
237 if (pForm) {
238 int trans = pForm->m_iTransparency;
239 if ((trans & PDFTRANS_ISOLATED) || (trans & PDFTRANS_GROUP))
240 return true;
241 }
242 }
243
244 return false;
245 }
246
FPDFPageObj_GetType(FPDF_PAGEOBJECT pageObject)247 FPDF_EXPORT int FPDF_CALLCONV FPDFPageObj_GetType(FPDF_PAGEOBJECT pageObject) {
248 if (!pageObject)
249 return FPDF_PAGEOBJ_UNKNOWN;
250
251 CPDF_PageObject* pPageObj = CPDFPageObjectFromFPDFPageObject(pageObject);
252 return pPageObj->GetType();
253 }
254
FPDFPage_GenerateContent(FPDF_PAGE page)255 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_GenerateContent(FPDF_PAGE page) {
256 CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
257 if (!IsPageObject(pPage))
258 return false;
259
260 CPDF_PageContentGenerator CG(pPage);
261 CG.GenerateContent();
262 return true;
263 }
264
265 FPDF_EXPORT void FPDF_CALLCONV
FPDFPageObj_Transform(FPDF_PAGEOBJECT page_object,double a,double b,double c,double d,double e,double f)266 FPDFPageObj_Transform(FPDF_PAGEOBJECT page_object,
267 double a,
268 double b,
269 double c,
270 double d,
271 double e,
272 double f) {
273 CPDF_PageObject* pPageObj = CPDFPageObjectFromFPDFPageObject(page_object);
274 if (!pPageObj)
275 return;
276
277 CFX_Matrix matrix((float)a, (float)b, (float)c, (float)d, (float)e, (float)f);
278 pPageObj->Transform(matrix);
279 }
280
281 FPDF_EXPORT void FPDF_CALLCONV
FPDFPageObj_SetBlendMode(FPDF_PAGEOBJECT page_object,FPDF_BYTESTRING blend_mode)282 FPDFPageObj_SetBlendMode(FPDF_PAGEOBJECT page_object,
283 FPDF_BYTESTRING blend_mode) {
284 CPDF_PageObject* pPageObj = CPDFPageObjectFromFPDFPageObject(page_object);
285 if (!pPageObj)
286 return;
287
288 pPageObj->m_GeneralState.SetBlendMode(blend_mode);
289 pPageObj->SetDirty(true);
290 }
291
FPDFPage_TransformAnnots(FPDF_PAGE page,double a,double b,double c,double d,double e,double f)292 FPDF_EXPORT void FPDF_CALLCONV FPDFPage_TransformAnnots(FPDF_PAGE page,
293 double a,
294 double b,
295 double c,
296 double d,
297 double e,
298 double f) {
299 CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
300 if (!pPage)
301 return;
302
303 CPDF_AnnotList AnnotList(pPage);
304 for (size_t i = 0; i < AnnotList.Count(); ++i) {
305 CPDF_Annot* pAnnot = AnnotList.GetAt(i);
306 CFX_Matrix matrix((float)a, (float)b, (float)c, (float)d, (float)e,
307 (float)f);
308 CFX_FloatRect rect = matrix.TransformRect(pAnnot->GetRect());
309
310 CPDF_Dictionary* pAnnotDict = pAnnot->GetAnnotDict();
311 CPDF_Array* pRectArray = pAnnotDict->GetArrayFor("Rect");
312 if (pRectArray)
313 pRectArray->Clear();
314 else
315 pRectArray = pAnnotDict->SetNewFor<CPDF_Array>("Rect");
316
317 pRectArray->AddNew<CPDF_Number>(rect.left);
318 pRectArray->AddNew<CPDF_Number>(rect.bottom);
319 pRectArray->AddNew<CPDF_Number>(rect.right);
320 pRectArray->AddNew<CPDF_Number>(rect.top);
321
322 // TODO(unknown): Transform AP's rectangle
323 }
324 }
325
FPDFPage_SetRotation(FPDF_PAGE page,int rotate)326 FPDF_EXPORT void FPDF_CALLCONV FPDFPage_SetRotation(FPDF_PAGE page,
327 int rotate) {
328 CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
329 if (!IsPageObject(pPage))
330 return;
331
332 rotate %= 4;
333 pPage->m_pFormDict->SetNewFor<CPDF_Number>("Rotate", rotate * 90);
334 }
335
FPDFPageObj_SetFillColor(FPDF_PAGEOBJECT page_object,unsigned int R,unsigned int G,unsigned int B,unsigned int A)336 FPDF_BOOL FPDFPageObj_SetFillColor(FPDF_PAGEOBJECT page_object,
337 unsigned int R,
338 unsigned int G,
339 unsigned int B,
340 unsigned int A) {
341 if (!page_object || R > 255 || G > 255 || B > 255 || A > 255)
342 return false;
343
344 float rgb[3] = {R / 255.f, G / 255.f, B / 255.f};
345 auto* pPageObj = CPDFPageObjectFromFPDFPageObject(page_object);
346 pPageObj->m_GeneralState.SetFillAlpha(A / 255.f);
347 pPageObj->m_ColorState.SetFillColor(
348 CPDF_ColorSpace::GetStockCS(PDFCS_DEVICERGB), rgb, 3);
349 pPageObj->SetDirty(true);
350 return true;
351 }
352
353 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDFPageObj_GetBounds(FPDF_PAGEOBJECT pageObject,float * left,float * bottom,float * right,float * top)354 FPDFPageObj_GetBounds(FPDF_PAGEOBJECT pageObject,
355 float* left,
356 float* bottom,
357 float* right,
358 float* top) {
359 if (!pageObject)
360 return false;
361
362 CPDF_PageObject* pPageObj = CPDFPageObjectFromFPDFPageObject(pageObject);
363 CFX_FloatRect bbox = pPageObj->GetRect();
364 *left = bbox.left;
365 *bottom = bbox.bottom;
366 *right = bbox.right;
367 *top = bbox.top;
368 return true;
369 }
370