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