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 "fpdfsdk/include/fsdk_define.h"
10 #include "public/fpdf_formfill.h"
11 
12 #ifdef PDF_ENABLE_XFA
13 #include "fpdfsdk/include/fpdfxfa/fpdfxfa_app.h"
14 #include "fpdfsdk/include/fpdfxfa/fpdfxfa_doc.h"
15 #include "fpdfsdk/include/fpdfxfa/fpdfxfa_page.h"
16 #endif  // PDF_ENABLE_XFA
17 
18 #if _FX_OS_ == _FX_ANDROID_
19 #include "time.h"
20 #else
21 #include <ctime>
22 #endif
23 
FPDF_CreateNewDocument()24 DLLEXPORT FPDF_DOCUMENT STDCALL FPDF_CreateNewDocument() {
25   CPDF_Document* pDoc = new CPDF_Document;
26   pDoc->CreateNewDoc();
27   time_t currentTime;
28 
29   CFX_ByteString DateStr;
30 
31   if (FSDK_IsSandBoxPolicyEnabled(FPDF_POLICY_MACHINETIME_ACCESS)) {
32     if (-1 != time(&currentTime)) {
33       tm* pTM = localtime(&currentTime);
34       if (pTM) {
35         DateStr.Format("D:%04d%02d%02d%02d%02d%02d", pTM->tm_year + 1900,
36                        pTM->tm_mon + 1, pTM->tm_mday, pTM->tm_hour, pTM->tm_min,
37                        pTM->tm_sec);
38       }
39     }
40   }
41 
42   CPDF_Dictionary* pInfoDict = NULL;
43   pInfoDict = pDoc->GetInfo();
44   if (pInfoDict) {
45     if (FSDK_IsSandBoxPolicyEnabled(FPDF_POLICY_MACHINETIME_ACCESS))
46       pInfoDict->SetAt("CreationDate", new CPDF_String(DateStr, FALSE));
47     pInfoDict->SetAt("Creator", new CPDF_String(L"PDFium"));
48   }
49 
50   return FPDFDocumentFromCPDFDocument(pDoc);
51 }
52 
FPDFPage_Delete(FPDF_DOCUMENT document,int page_index)53 DLLEXPORT void STDCALL FPDFPage_Delete(FPDF_DOCUMENT document, int page_index) {
54   CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
55   if (!pDoc || page_index < 0 || page_index >= pDoc->GetPageCount())
56     return;
57 
58   pDoc->DeletePage(page_index);
59 }
60 
FPDFPage_New(FPDF_DOCUMENT document,int page_index,double width,double height)61 DLLEXPORT FPDF_PAGE STDCALL FPDFPage_New(FPDF_DOCUMENT document,
62                                          int page_index,
63                                          double width,
64                                          double height) {
65   CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
66   if (!pDoc)
67     return nullptr;
68 
69   if (page_index < 0)
70     page_index = 0;
71   if (pDoc->GetPageCount() < page_index)
72     page_index = pDoc->GetPageCount();
73 
74   CPDF_Dictionary* pPageDict = pDoc->CreateNewPage(page_index);
75   if (!pPageDict)
76     return NULL;
77   CPDF_Array* pMediaBoxArray = new CPDF_Array;
78   pMediaBoxArray->Add(new CPDF_Number(0));
79   pMediaBoxArray->Add(new CPDF_Number(0));
80   pMediaBoxArray->Add(new CPDF_Number(FX_FLOAT(width)));
81   pMediaBoxArray->Add(new CPDF_Number(FX_FLOAT(height)));
82 
83   pPageDict->SetAt("MediaBox", pMediaBoxArray);
84   pPageDict->SetAt("Rotate", new CPDF_Number(0));
85   pPageDict->SetAt("Resources", new CPDF_Dictionary);
86 
87 #ifdef PDF_ENABLE_XFA
88   CPDFXFA_Page* pPage =
89       new CPDFXFA_Page((CPDFXFA_Document*)document, page_index);
90   pPage->LoadPDFPage(pPageDict);
91 #else   // PDF_ENABLE_XFA
92   CPDF_Page* pPage = new CPDF_Page;
93   pPage->Load(pDoc, pPageDict);
94   pPage->ParseContent();
95 #endif  // PDF_ENABLE_XFA
96 
97   return pPage;
98 }
99 
FPDFPage_GetRotation(FPDF_PAGE page)100 DLLEXPORT int STDCALL FPDFPage_GetRotation(FPDF_PAGE page) {
101   CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
102   if (!pPage || !pPage->m_pFormDict || !pPage->m_pFormDict->KeyExist("Type") ||
103       !pPage->m_pFormDict->GetElement("Type")->GetDirect() ||
104       pPage->m_pFormDict->GetElement("Type")->GetDirect()->GetString().Compare(
105           "Page")) {
106     return -1;
107   }
108   CPDF_Dictionary* pDict = pPage->m_pFormDict;
109   if (!pDict)
110     return -1;
111 
112   while (pDict) {
113     if (pDict->KeyExist("Rotate")) {
114       CPDF_Object* pRotateObj = pDict->GetElement("Rotate")->GetDirect();
115       return pRotateObj ? pRotateObj->GetInteger() / 90 : 0;
116     }
117     if (!pDict->KeyExist("Parent"))
118       break;
119 
120     pDict = ToDictionary(pDict->GetElement("Parent")->GetDirect());
121   }
122 
123   return 0;
124 }
125 
FPDFPage_InsertObject(FPDF_PAGE page,FPDF_PAGEOBJECT page_obj)126 DLLEXPORT void STDCALL FPDFPage_InsertObject(FPDF_PAGE page,
127                                              FPDF_PAGEOBJECT page_obj) {
128   CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
129   if (!pPage || !pPage->m_pFormDict || !pPage->m_pFormDict->KeyExist("Type") ||
130       !pPage->m_pFormDict->GetElement("Type")->GetDirect() ||
131       pPage->m_pFormDict->GetElement("Type")->GetDirect()->GetString().Compare(
132           "Page")) {
133     return;
134   }
135   CPDF_PageObject* pPageObj = (CPDF_PageObject*)page_obj;
136   if (!pPageObj)
137     return;
138   FX_POSITION LastPersition = pPage->GetLastObjectPosition();
139 
140   pPage->InsertObject(LastPersition, pPageObj);
141   switch (pPageObj->m_Type) {
142     case FPDF_PAGEOBJ_PATH: {
143       CPDF_PathObject* pPathObj = (CPDF_PathObject*)pPageObj;
144       pPathObj->CalcBoundingBox();
145       break;
146     }
147     case FPDF_PAGEOBJ_TEXT: {
148       //	CPDF_PathObject* pPathObj = (CPDF_PathObject*)pPageObj;
149       //	pPathObj->CalcBoundingBox();
150       break;
151     }
152     case FPDF_PAGEOBJ_IMAGE: {
153       CPDF_ImageObject* pImageObj = (CPDF_ImageObject*)pPageObj;
154       pImageObj->CalcBoundingBox();
155       break;
156     }
157     case FPDF_PAGEOBJ_SHADING: {
158       CPDF_ShadingObject* pShadingObj = (CPDF_ShadingObject*)pPageObj;
159       pShadingObj->CalcBoundingBox();
160       break;
161     }
162     case FPDF_PAGEOBJ_FORM: {
163       CPDF_FormObject* pFormObj = (CPDF_FormObject*)pPageObj;
164       pFormObj->CalcBoundingBox();
165       break;
166     }
167     default:
168       break;
169   }
170 }
171 
FPDFPage_CountObject(FPDF_PAGE page)172 DLLEXPORT int STDCALL FPDFPage_CountObject(FPDF_PAGE page) {
173   CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
174   if (!pPage || !pPage->m_pFormDict || !pPage->m_pFormDict->KeyExist("Type") ||
175       !pPage->m_pFormDict->GetElement("Type")->GetDirect() ||
176       pPage->m_pFormDict->GetElement("Type")->GetDirect()->GetString().Compare(
177           "Page")) {
178     return -1;
179   }
180   return pPage->CountObjects();
181 }
182 
FPDFPage_GetObject(FPDF_PAGE page,int index)183 DLLEXPORT FPDF_PAGEOBJECT STDCALL FPDFPage_GetObject(FPDF_PAGE page,
184                                                      int index) {
185   CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
186   if (!pPage || !pPage->m_pFormDict || !pPage->m_pFormDict->KeyExist("Type") ||
187       pPage->m_pFormDict->GetElement("Type")->GetDirect()->GetString().Compare(
188           "Page")) {
189     return NULL;
190   }
191   return pPage->GetObjectByIndex(index);
192 }
193 
FPDFPage_HasTransparency(FPDF_PAGE page)194 DLLEXPORT FPDF_BOOL STDCALL FPDFPage_HasTransparency(FPDF_PAGE page) {
195   CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
196   return pPage && pPage->BackgroundAlphaNeeded();
197 }
198 
199 DLLEXPORT FPDF_BOOL STDCALL
FPDFPageObj_HasTransparency(FPDF_PAGEOBJECT pageObject)200 FPDFPageObj_HasTransparency(FPDF_PAGEOBJECT pageObject) {
201   if (!pageObject)
202     return FALSE;
203   CPDF_PageObject* pPageObj = (CPDF_PageObject*)pageObject;
204 
205   const CPDF_GeneralStateData* pGeneralState = pPageObj->m_GeneralState;
206   int blend_type =
207       pGeneralState ? pGeneralState->m_BlendType : FXDIB_BLEND_NORMAL;
208   if (blend_type != FXDIB_BLEND_NORMAL)
209     return TRUE;
210 
211   CPDF_Dictionary* pSMaskDict =
212       pGeneralState ? ToDictionary(pGeneralState->m_pSoftMask) : NULL;
213   if (pSMaskDict)
214     return TRUE;
215 
216   if (pGeneralState && pGeneralState->m_FillAlpha != 1.0f)
217     return TRUE;
218 
219   if (pPageObj->m_Type == PDFPAGE_PATH) {
220     if (pGeneralState && pGeneralState->m_StrokeAlpha != 1.0f)
221       return TRUE;
222   }
223 
224   if (pPageObj->m_Type == PDFPAGE_FORM) {
225     CPDF_FormObject* pFormObj = (CPDF_FormObject*)pPageObj;
226     if (pFormObj->m_pForm &&
227         (pFormObj->m_pForm->m_Transparency & PDFTRANS_ISOLATED))
228       return TRUE;
229     if (pFormObj->m_pForm &&
230         (!(pFormObj->m_pForm->m_Transparency & PDFTRANS_ISOLATED) &&
231          (pFormObj->m_pForm->m_Transparency & PDFTRANS_GROUP)))
232       return TRUE;
233   }
234   return FALSE;
235 }
236 
FPDFPage_GenerateContent(FPDF_PAGE page)237 DLLEXPORT FPDF_BOOL STDCALL FPDFPage_GenerateContent(FPDF_PAGE page) {
238   CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
239   if (!pPage || !pPage->m_pFormDict || !pPage->m_pFormDict->KeyExist("Type") ||
240       !pPage->m_pFormDict->GetElement("Type")->GetDirect() ||
241       pPage->m_pFormDict->GetElement("Type")->GetDirect()->GetString().Compare(
242           "Page")) {
243     return FALSE;
244   }
245   CPDF_PageContentGenerate CG(pPage);
246   CG.GenerateContent();
247 
248   return TRUE;
249 }
250 
FPDFPageObj_Transform(FPDF_PAGEOBJECT page_object,double a,double b,double c,double d,double e,double f)251 DLLEXPORT void STDCALL FPDFPageObj_Transform(FPDF_PAGEOBJECT page_object,
252                                              double a,
253                                              double b,
254                                              double c,
255                                              double d,
256                                              double e,
257                                              double f) {
258   CPDF_PageObject* pPageObj = (CPDF_PageObject*)page_object;
259   if (!pPageObj)
260     return;
261 
262   CFX_Matrix matrix((FX_FLOAT)a, (FX_FLOAT)b, (FX_FLOAT)c, (FX_FLOAT)d,
263                     (FX_FLOAT)e, (FX_FLOAT)f);
264   pPageObj->Transform(matrix);
265 }
FPDFPage_TransformAnnots(FPDF_PAGE page,double a,double b,double c,double d,double e,double f)266 DLLEXPORT void STDCALL FPDFPage_TransformAnnots(FPDF_PAGE page,
267                                                 double a,
268                                                 double b,
269                                                 double c,
270                                                 double d,
271                                                 double e,
272                                                 double f) {
273   CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
274   if (!pPage)
275     return;
276   CPDF_AnnotList AnnotList(pPage);
277   for (size_t i = 0; i < AnnotList.Count(); ++i) {
278     CPDF_Annot* pAnnot = AnnotList.GetAt(i);
279     // transformAnnots Rectangle
280     CPDF_Rect rect;
281     pAnnot->GetRect(rect);
282     CFX_Matrix matrix((FX_FLOAT)a, (FX_FLOAT)b, (FX_FLOAT)c, (FX_FLOAT)d,
283                       (FX_FLOAT)e, (FX_FLOAT)f);
284     rect.Transform(&matrix);
285     CPDF_Array* pRectArray = NULL;
286     pRectArray = pAnnot->GetAnnotDict()->GetArray("Rect");
287     if (!pRectArray)
288       pRectArray = new CPDF_Array;
289     pRectArray->SetAt(0, new CPDF_Number(rect.left));
290     pRectArray->SetAt(1, new CPDF_Number(rect.bottom));
291     pRectArray->SetAt(2, new CPDF_Number(rect.right));
292     pRectArray->SetAt(3, new CPDF_Number(rect.top));
293     pAnnot->GetAnnotDict()->SetAt("Rect", pRectArray);
294 
295     // Transform AP's rectangle
296     // To Do
297   }
298 }
299 
FPDFPage_SetRotation(FPDF_PAGE page,int rotate)300 DLLEXPORT void STDCALL FPDFPage_SetRotation(FPDF_PAGE page, int rotate) {
301   CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
302   if (!pPage || !pPage->m_pFormDict || !pPage->m_pFormDict->KeyExist("Type") ||
303       !pPage->m_pFormDict->GetElement("Type")->GetDirect() ||
304       pPage->m_pFormDict->GetElement("Type")->GetDirect()->GetString().Compare(
305           "Page")) {
306     return;
307   }
308   CPDF_Dictionary* pDict = pPage->m_pFormDict;
309   rotate %= 4;
310 
311   pDict->SetAt("Rotate", new CPDF_Number(rotate * 90));
312 }
313