Standalone checkout gets buildtools.
[pdfium.git] / fpdfsdk / src / fpdf_transformpage.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_transformpage.h"
8 #include "../include/fsdk_define.h"
9
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
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
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
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
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
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
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
212 DLLEXPORT void STDCALL FPDF_DestroyClipPath(FPDF_CLIPPATH clipPath)
213 {
214         if(clipPath)
215                 delete (CPDF_ClipPath*)clipPath;
216 }
217
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
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