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