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