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