Revert "FX_BOOL considered harmful, part 2."
[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 FPDF_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((const uint8_t*)" 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     delete (CPDF_ClipPath*)clipPath;
215 }
216
217 void OutputPath(CFX_ByteTextBuf& buf, CPDF_Path path)
218 {
219         const CFX_PathData* pPathData = path;
220         if (pPathData == NULL) return;
221
222         FX_PATHPOINT* pPoints = pPathData->GetPoints();
223
224         if (path.IsRect()) {
225                 buf << (pPoints[0].m_PointX) << " " << (pPoints[0].m_PointY) << " "
226                         << (pPoints[2].m_PointX - pPoints[0].m_PointX) << " "
227                         << (pPoints[2].m_PointY - pPoints[0].m_PointY) << " re\n";
228                 return;
229         }
230
231         CFX_ByteString temp;
232         for (int i = 0; i < pPathData->GetPointCount(); i ++) {
233                 buf << (pPoints[i].m_PointX) << " " << (pPoints[i].m_PointY);
234                 int point_type = pPoints[i].m_Flag & FXPT_TYPE;
235                 if (point_type == FXPT_MOVETO)
236                         buf << " m\n";
237                 else if (point_type == FXPT_BEZIERTO) {
238                         buf << " " << (pPoints[i+1].m_PointX) << " " << (pPoints[i+1].m_PointY) << " " <<
239                                 (pPoints[i+2].m_PointX) << " " << (pPoints[i+2].m_PointY);
240                         if (pPoints[i+2].m_Flag & FXPT_CLOSEFIGURE)
241                                 buf << " c h\n";
242                         else
243                                 buf << " c\n";
244                         i += 2;
245                 } else if (point_type == FXPT_LINETO) {
246                         if (pPoints[i].m_Flag & FXPT_CLOSEFIGURE)
247                                 buf << " l h\n";
248                         else
249                                 buf << " l\n";
250                 }
251         }
252 }
253
254 DLLEXPORT void STDCALL FPDFPage_InsertClipPath(FPDF_PAGE page,FPDF_CLIPPATH clipPath)
255 {
256         if(!page)
257                 return;
258         CPDF_Page* pPage = (CPDF_Page*)page;
259         CPDF_Dictionary* pPageDic = pPage->m_pFormDict;
260         CPDF_Object* pContentObj = pPageDic ? pPageDic->GetElement("Contents") : NULL;
261         if(!pContentObj)
262                 pContentObj = pPageDic ? pPageDic->GetArray("Contents") : NULL;
263         if(!pContentObj)
264                 return;
265
266         CFX_ByteTextBuf strClip;
267         CPDF_ClipPath* pClipPath = (CPDF_ClipPath*)clipPath;
268         FX_DWORD i;
269         for (i = 0; i < pClipPath->GetPathCount(); i ++) {
270                 CPDF_Path path = pClipPath->GetPath(i);
271                 int iClipType = pClipPath->GetClipType(i);
272                 if (path.GetPointCount() == 0) {
273                         // Empty clipping (totally clipped out)
274                         strClip << "0 0 m W n ";
275                 } else {
276                         OutputPath(strClip, path);
277                         if (iClipType == FXFILL_WINDING)
278                                 strClip << "W n\n";
279                         else
280                                 strClip << "W* n\n";
281                 }
282         }
283         CPDF_Dictionary* pDic = new CPDF_Dictionary;
284         CPDF_Stream* pStream = new CPDF_Stream(NULL,0, pDic);
285         pStream->SetData(strClip.GetBuffer(), strClip.GetSize(), FALSE, FALSE);
286         CPDF_Document* pDoc = pPage->m_pDocument;
287         if(!pDoc)
288                 return;
289         pDoc->AddIndirectObject(pStream);
290
291         CPDF_Array* pContentArray = NULL;
292         if (pContentObj && pContentObj->GetType() == PDFOBJ_ARRAY)
293         {
294                 pContentArray = (CPDF_Array*)pContentObj;
295                 CPDF_Reference* pRef = new CPDF_Reference(pDoc, pStream->GetObjNum());
296                 pContentArray->InsertAt(0, pRef);
297         }
298         else if(pContentObj && pContentObj->GetType() == PDFOBJ_REFERENCE)
299         {
300                 CPDF_Reference* pReference = (CPDF_Reference*)pContentObj;
301                 CPDF_Object* pDirectObj = pReference->GetDirect();
302                 if(pDirectObj != NULL)
303                 {
304                         if(pDirectObj->GetType() == PDFOBJ_ARRAY)
305                         {
306                                 pContentArray = (CPDF_Array*)pDirectObj;
307                                 CPDF_Reference* pRef = new CPDF_Reference(pDoc, pStream->GetObjNum());
308                                 pContentArray->InsertAt(0, pRef);
309                         }
310                         else if(pDirectObj->GetType() == PDFOBJ_STREAM)
311                         {
312                                 pContentArray = new CPDF_Array();
313                                 pContentArray->AddReference(pDoc,pStream->GetObjNum());
314                                 pContentArray->AddReference(pDoc,pDirectObj->GetObjNum());
315                                 pPageDic->SetAtReference("Contents", pDoc, pDoc->AddIndirectObject(pContentArray));
316                         }
317                 }
318         }
319 }
320