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_transformpage.h"
8 #include "../include/fsdk_define.h"
9 
FPDFPage_SetMediaBox(FPDF_PAGE page,float left,float bottom,float right,float top)10 DLLEXPORT void STDCALL FPDFPage_SetMediaBox(FPDF_PAGE page, float left, float bottom, float right, float top)
11 {
12 	if(!page)
13 		return;
14 
15 	CPDF_Page* pPage = (CPDF_Page*)page;
16 	CPDF_Dictionary* pPageDict = pPage->m_pFormDict;
17 	CPDF_Array* pMediaBoxArray = new CPDF_Array;
18 	pMediaBoxArray->Add(new CPDF_Number(left));
19 	pMediaBoxArray->Add(new CPDF_Number(bottom));
20 	pMediaBoxArray->Add(new CPDF_Number(FX_FLOAT(right)));
21 	pMediaBoxArray->Add(new CPDF_Number(FX_FLOAT(top)));
22 	pPageDict->SetAt("MediaBox", pMediaBoxArray);
23 }
24 
25 
FPDFPage_SetCropBox(FPDF_PAGE page,float left,float bottom,float right,float top)26 DLLEXPORT void STDCALL FPDFPage_SetCropBox(FPDF_PAGE page, float left, float bottom, float right, float top)
27 {
28 	if(!page)
29 		return;
30 
31 	CPDF_Page* pPage = (CPDF_Page*)page;
32 	CPDF_Dictionary* pPageDict = pPage->m_pFormDict;
33 	CPDF_Array* pCropBoxArray = new CPDF_Array;
34 	pCropBoxArray->Add(new CPDF_Number(left));
35 	pCropBoxArray->Add(new CPDF_Number(bottom));
36 	pCropBoxArray->Add(new CPDF_Number(FX_FLOAT(right)));
37 	pCropBoxArray->Add(new CPDF_Number(FX_FLOAT(top)));
38 	pPageDict->SetAt("CropBox", pCropBoxArray);
39 }
40 
41 
FPDFPage_GetMediaBox(FPDF_PAGE page,float * left,float * bottom,float * right,float * top)42 DLLEXPORT FX_BOOL STDCALL FPDFPage_GetMediaBox(FPDF_PAGE page, float* left, float* bottom, float* right, float* top)
43 {
44 	if(!page)
45 		return FALSE;
46 	CPDF_Page* pPage = (CPDF_Page*)page;
47 	CPDF_Dictionary* pPageDict = pPage->m_pFormDict;
48 	CPDF_Array* pArray = pPageDict->GetArray("MediaBox");
49 	if(pArray)
50 	{
51 		*left = pArray->GetFloat(0);
52 		*bottom = pArray->GetFloat(1);
53 		*right = pArray->GetFloat(2);
54 		*top = pArray->GetFloat(3);
55 		return TRUE;
56 	}
57 	return FALSE;
58 }
59 
FPDFPage_GetCropBox(FPDF_PAGE page,float * left,float * bottom,float * right,float * top)60 DLLEXPORT FPDF_BOOL STDCALL FPDFPage_GetCropBox(FPDF_PAGE page, float* left, float* bottom, float* right, float* top)
61 {
62 	if(!page)
63 		return FALSE;
64 	CPDF_Page* pPage = (CPDF_Page*)page;
65 	CPDF_Dictionary* pPageDict = pPage->m_pFormDict;
66 	CPDF_Array* pArray = pPageDict->GetArray("CropBox");
67 	if(pArray)
68 	{
69 		*left = pArray->GetFloat(0);
70 		*bottom = pArray->GetFloat(1);
71 		*right = pArray->GetFloat(2);
72 		*top = pArray->GetFloat(3);
73 		return TRUE;
74 	}
75 	return FALSE;
76 }
77 
FPDFPage_TransFormWithClip(FPDF_PAGE page,FS_MATRIX * matrix,FS_RECTF * clipRect)78 DLLEXPORT FPDF_BOOL STDCALL FPDFPage_TransFormWithClip(FPDF_PAGE page, FS_MATRIX* matrix, FS_RECTF* clipRect)
79 {
80 	if(!page)
81 		return FALSE;
82 
83 	CFX_ByteTextBuf textBuf;
84 	textBuf<<"q ";
85 	CFX_FloatRect rect(clipRect->left, clipRect->bottom, clipRect->right, clipRect->top);
86 	rect.Normalize();
87 	CFX_ByteString bsClipping;
88 	bsClipping.Format("%f %f %f %f re W* n ", rect.left, rect.bottom, rect.Width(), rect.Height());
89 	textBuf<<bsClipping;
90 
91 	CFX_ByteString bsMatix;
92 	bsMatix.Format("%f %f %f %f %f %f cm ", matrix->a, matrix->b,matrix->c,matrix->d,matrix->e,matrix->f);
93 	textBuf<<bsMatix;
94 
95 
96 	CPDF_Page* pPage = (CPDF_Page*)page;
97 	CPDF_Dictionary* pPageDic = pPage->m_pFormDict;
98 	CPDF_Object* pContentObj = pPageDic ? pPageDic->GetElement("Contents") : NULL;
99 	if(!pContentObj)
100 		pContentObj = pPageDic ? pPageDic->GetArray("Contents") : NULL;
101 	if(!pContentObj)
102 		return FALSE;
103 
104 	CPDF_Dictionary* pDic = new CPDF_Dictionary;
105 	CPDF_Stream* pStream = new CPDF_Stream(NULL,0, pDic);
106 	pStream->SetData(textBuf.GetBuffer(), textBuf.GetSize(), FALSE, FALSE);
107 	CPDF_Document* pDoc = pPage->m_pDocument;
108 	if(!pDoc)
109 		return FALSE;
110 	pDoc->AddIndirectObject(pStream);
111 
112 	pDic = new CPDF_Dictionary;
113 	CPDF_Stream* pEndStream = new CPDF_Stream(NULL,0, pDic);
114 	pEndStream->SetData((FX_LPCBYTE)" Q", 2, FALSE, FALSE);
115 	pDoc->AddIndirectObject(pEndStream);
116 
117 	CPDF_Array* pContentArray = NULL;
118 	if (pContentObj && pContentObj->GetType() == PDFOBJ_ARRAY)
119 	{
120 		pContentArray = (CPDF_Array*)pContentObj;
121 		CPDF_Reference* pRef = new CPDF_Reference(pDoc, pStream->GetObjNum());
122 		pContentArray->InsertAt(0, pRef);
123 		pContentArray->AddReference(pDoc,pEndStream);
124 
125 	}
126 	else if(pContentObj && pContentObj->GetType() == PDFOBJ_REFERENCE)
127 	{
128 		CPDF_Reference* pReference = (CPDF_Reference*)pContentObj;
129 		CPDF_Object* pDirectObj = pReference->GetDirect();
130 		if(pDirectObj != NULL)
131 		{
132 			if(pDirectObj->GetType() == PDFOBJ_ARRAY)
133 			{
134 				pContentArray = (CPDF_Array*)pDirectObj;
135 				CPDF_Reference* pRef = new CPDF_Reference(pDoc, pStream->GetObjNum());
136 				pContentArray->InsertAt(0, pRef);
137 				pContentArray->AddReference(pDoc,pEndStream);
138 			}
139 			else if(pDirectObj->GetType() == PDFOBJ_STREAM)
140 			{
141 				pContentArray = new CPDF_Array();
142 				pContentArray->AddReference(pDoc,pStream->GetObjNum());
143 				pContentArray->AddReference(pDoc,pDirectObj->GetObjNum());
144 				pContentArray->AddReference(pDoc, pEndStream);
145 				pPageDic->SetAtReference("Contents", pDoc, pDoc->AddIndirectObject(pContentArray));
146 			}
147 		}
148 	}
149 
150 	//Need to transform the patterns as well.
151 	CPDF_Dictionary* pRes = pPageDic->GetDict(FX_BSTRC("Resources"));
152 	if(pRes)
153 	{
154 		CPDF_Dictionary* pPattenDict = pRes->GetDict(FX_BSTRC("Pattern"));
155 		if(pPattenDict)
156 		{
157 			FX_POSITION pos = pPattenDict->GetStartPos();
158 			while(pos)
159 			{
160 				CPDF_Dictionary* pDict = NULL;
161 				CFX_ByteString key;
162 				CPDF_Object* pObj = pPattenDict->GetNextElement(pos, key);
163 				if(pObj->GetType() == PDFOBJ_REFERENCE)
164 					pObj = pObj->GetDirect();
165 				if(pObj->GetType() == PDFOBJ_DICTIONARY)
166 				{
167 					pDict = (CPDF_Dictionary*)pObj;
168 				}
169 				else if(pObj->GetType() == PDFOBJ_STREAM)
170 				{
171 					pDict = ((CPDF_Stream*)pObj)->GetDict();
172 				}
173 				else
174 					continue;
175 
176 				CFX_AffineMatrix m = pDict->GetMatrix(FX_BSTRC("Matrix"));
177 				CFX_AffineMatrix t = *(CFX_AffineMatrix*)matrix;
178 				m.Concat(t);
179 				pDict->SetAtMatrix(FX_BSTRC("Matrix"), m);
180 			}
181 		}
182 	}
183 
184 	return TRUE;
185 }
186 
FPDFPageObj_TransformClipPath(FPDF_PAGEOBJECT page_object,double a,double b,double c,double d,double e,double f)187 DLLEXPORT void STDCALL FPDFPageObj_TransformClipPath(FPDF_PAGEOBJECT page_object,double a, double b, double c, double d, double e, double f)
188 {
189 	CPDF_PageObject* pPageObj = (CPDF_PageObject*)page_object;
190 	if(pPageObj == NULL)
191 		return;
192 	CFX_AffineMatrix matrix((FX_FLOAT)a,(FX_FLOAT)b,(FX_FLOAT)c,(FX_FLOAT)d,(FX_FLOAT)e,(FX_FLOAT)f);
193 
194 	//Special treatment to shading object, because the ClipPath for shading object is already transformed.
195 	if(pPageObj->m_Type != PDFPAGE_SHADING)
196 		pPageObj->TransformClipPath(matrix);
197 	pPageObj->TransformGeneralState(matrix);
198 }
199 
200 
FPDF_CreateClipPath(float left,float bottom,float right,float top)201 DLLEXPORT FPDF_CLIPPATH STDCALL FPDF_CreateClipPath(float left, float bottom, float right, float top)
202 {
203 	CPDF_ClipPath* pNewClipPath = new CPDF_ClipPath();
204 	pNewClipPath->GetModify();
205 	CPDF_Path Path;
206 	Path.GetModify();
207 	Path.AppendRect(left, bottom, right, top);
208 	pNewClipPath->AppendPath(Path, FXFILL_ALTERNATE, FALSE);
209 	return pNewClipPath;
210 }
211 
FPDF_DestroyClipPath(FPDF_CLIPPATH clipPath)212 DLLEXPORT void STDCALL FPDF_DestroyClipPath(FPDF_CLIPPATH clipPath)
213 {
214 	if(clipPath)
215 		delete (CPDF_ClipPath*)clipPath;
216 }
217 
OutputPath(CFX_ByteTextBuf & buf,CPDF_Path path)218 void OutputPath(CFX_ByteTextBuf& buf, CPDF_Path path)
219 {
220 	const CFX_PathData* pPathData = path;
221 	if (pPathData == NULL) return;
222 
223 	FX_PATHPOINT* pPoints = pPathData->GetPoints();
224 
225 	if (path.IsRect()) {
226 		buf << (pPoints[0].m_PointX) << " " << (pPoints[0].m_PointY) << " "
227 			<< (pPoints[2].m_PointX - pPoints[0].m_PointX) << " "
228 			<< (pPoints[2].m_PointY - pPoints[0].m_PointY) << " re\n";
229 		return;
230 	}
231 
232 	CFX_ByteString temp;
233 	for (int i = 0; i < pPathData->GetPointCount(); i ++) {
234 		buf << (pPoints[i].m_PointX) << " " << (pPoints[i].m_PointY);
235 		int point_type = pPoints[i].m_Flag & FXPT_TYPE;
236 		if (point_type == FXPT_MOVETO)
237 			buf << " m\n";
238 		else if (point_type == FXPT_BEZIERTO) {
239 			buf << " " << (pPoints[i+1].m_PointX) << " " << (pPoints[i+1].m_PointY) << " " <<
240 				(pPoints[i+2].m_PointX) << " " << (pPoints[i+2].m_PointY);
241 			if (pPoints[i+2].m_Flag & FXPT_CLOSEFIGURE)
242 				buf << " c h\n";
243 			else
244 				buf << " c\n";
245 			i += 2;
246 		} else if (point_type == FXPT_LINETO) {
247 			if (pPoints[i].m_Flag & FXPT_CLOSEFIGURE)
248 				buf << " l h\n";
249 			else
250 				buf << " l\n";
251 		}
252 	}
253 }
254 
FPDFPage_InsertClipPath(FPDF_PAGE page,FPDF_CLIPPATH clipPath)255 DLLEXPORT void STDCALL FPDFPage_InsertClipPath(FPDF_PAGE page,FPDF_CLIPPATH clipPath)
256 {
257 	if(!page)
258 		return;
259 	CPDF_Page* pPage = (CPDF_Page*)page;
260 	CPDF_Dictionary* pPageDic = pPage->m_pFormDict;
261 	CPDF_Object* pContentObj = pPageDic ? pPageDic->GetElement("Contents") : NULL;
262 	if(!pContentObj)
263 		pContentObj = pPageDic ? pPageDic->GetArray("Contents") : NULL;
264 	if(!pContentObj)
265 		return;
266 
267 	CFX_ByteTextBuf strClip;
268 	CPDF_ClipPath* pClipPath = (CPDF_ClipPath*)clipPath;
269 	FX_DWORD i;
270 	for (i = 0; i < pClipPath->GetPathCount(); i ++) {
271 		CPDF_Path path = pClipPath->GetPath(i);
272 		int iClipType = pClipPath->GetClipType(i);
273 		if (path.GetPointCount() == 0) {
274 			// Empty clipping (totally clipped out)
275 			strClip << "0 0 m W n ";
276 		} else {
277 			OutputPath(strClip, path);
278 			if (iClipType == FXFILL_WINDING)
279 				strClip << "W n\n";
280 			else
281 				strClip << "W* n\n";
282 		}
283 	}
284 	CPDF_Dictionary* pDic = new CPDF_Dictionary;
285 	CPDF_Stream* pStream = new CPDF_Stream(NULL,0, pDic);
286 	pStream->SetData(strClip.GetBuffer(), strClip.GetSize(), FALSE, FALSE);
287 	CPDF_Document* pDoc = pPage->m_pDocument;
288 	if(!pDoc)
289 		return;
290 	pDoc->AddIndirectObject(pStream);
291 
292 	CPDF_Array* pContentArray = NULL;
293 	if (pContentObj && pContentObj->GetType() == PDFOBJ_ARRAY)
294 	{
295 		pContentArray = (CPDF_Array*)pContentObj;
296 		CPDF_Reference* pRef = new CPDF_Reference(pDoc, pStream->GetObjNum());
297 		pContentArray->InsertAt(0, pRef);
298 	}
299 	else if(pContentObj && pContentObj->GetType() == PDFOBJ_REFERENCE)
300 	{
301 		CPDF_Reference* pReference = (CPDF_Reference*)pContentObj;
302 		CPDF_Object* pDirectObj = pReference->GetDirect();
303 		if(pDirectObj != NULL)
304 		{
305 			if(pDirectObj->GetType() == PDFOBJ_ARRAY)
306 			{
307 				pContentArray = (CPDF_Array*)pDirectObj;
308 				CPDF_Reference* pRef = new CPDF_Reference(pDoc, pStream->GetObjNum());
309 				pContentArray->InsertAt(0, pRef);
310 			}
311 			else if(pDirectObj->GetType() == PDFOBJ_STREAM)
312 			{
313 				pContentArray = new CPDF_Array();
314 				pContentArray->AddReference(pDoc,pStream->GetObjNum());
315 				pContentArray->AddReference(pDoc,pDirectObj->GetObjNum());
316 				pPageDic->SetAtReference("Contents", pDoc, pDoc->AddIndirectObject(pContentArray));
317 			}
318 		}
319 	}
320 }
321 
322