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