• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_edit.h"
8 
9 #include <algorithm>
10 #include <memory>
11 #include <utility>
12 
13 #include "core/fpdfapi/edit/cpdf_pagecontentgenerator.h"
14 #include "core/fpdfapi/page/cpdf_form.h"
15 #include "core/fpdfapi/page/cpdf_formobject.h"
16 #include "core/fpdfapi/page/cpdf_imageobject.h"
17 #include "core/fpdfapi/page/cpdf_page.h"
18 #include "core/fpdfapi/page/cpdf_pageobject.h"
19 #include "core/fpdfapi/page/cpdf_pathobject.h"
20 #include "core/fpdfapi/page/cpdf_shadingobject.h"
21 #include "core/fpdfapi/parser/cpdf_array.h"
22 #include "core/fpdfapi/parser/cpdf_document.h"
23 #include "core/fpdfapi/parser/cpdf_number.h"
24 #include "core/fpdfapi/parser/cpdf_string.h"
25 #include "core/fpdfdoc/cpdf_annot.h"
26 #include "core/fpdfdoc/cpdf_annotlist.h"
27 #include "fpdfsdk/fsdk_define.h"
28 #include "public/fpdf_formfill.h"
29 #include "third_party/base/logging.h"
30 #include "third_party/base/stl_util.h"
31 
32 #ifdef PDF_ENABLE_XFA
33 #include "fpdfsdk/fpdfxfa/cpdfxfa_context.h"
34 #include "fpdfsdk/fpdfxfa/cpdfxfa_page.h"
35 #endif  // PDF_ENABLE_XFA
36 
37 #if _FX_OS_ == _FX_OS_ANDROID_
38 #include <time.h>
39 #else
40 #include <ctime>
41 #endif
42 
43 namespace {
44 
45 static_assert(FPDF_PAGEOBJ_TEXT == CPDF_PageObject::TEXT,
46               "FPDF_PAGEOBJ_TEXT/CPDF_PageObject::TEXT mismatch");
47 static_assert(FPDF_PAGEOBJ_PATH == CPDF_PageObject::PATH,
48               "FPDF_PAGEOBJ_PATH/CPDF_PageObject::PATH mismatch");
49 static_assert(FPDF_PAGEOBJ_IMAGE == CPDF_PageObject::IMAGE,
50               "FPDF_PAGEOBJ_IMAGE/CPDF_PageObject::IMAGE mismatch");
51 static_assert(FPDF_PAGEOBJ_SHADING == CPDF_PageObject::SHADING,
52               "FPDF_PAGEOBJ_SHADING/CPDF_PageObject::SHADING mismatch");
53 static_assert(FPDF_PAGEOBJ_FORM == CPDF_PageObject::FORM,
54               "FPDF_PAGEOBJ_FORM/CPDF_PageObject::FORM mismatch");
55 
IsPageObject(CPDF_Page * pPage)56 bool IsPageObject(CPDF_Page* pPage) {
57   if (!pPage || !pPage->m_pFormDict || !pPage->m_pFormDict->KeyExist("Type"))
58     return false;
59 
60   CPDF_Object* pObject = pPage->m_pFormDict->GetObjectFor("Type")->GetDirect();
61   return pObject && !pObject->GetString().Compare("Page");
62 }
63 
CalcBoundingBox(CPDF_PageObject * pPageObj)64 void CalcBoundingBox(CPDF_PageObject* pPageObj) {
65   switch (pPageObj->GetType()) {
66     case CPDF_PageObject::TEXT: {
67       break;
68     }
69     case CPDF_PageObject::PATH: {
70       CPDF_PathObject* pPathObj = pPageObj->AsPath();
71       pPathObj->CalcBoundingBox();
72       break;
73     }
74     case CPDF_PageObject::IMAGE: {
75       CPDF_ImageObject* pImageObj = pPageObj->AsImage();
76       pImageObj->CalcBoundingBox();
77       break;
78     }
79     case CPDF_PageObject::SHADING: {
80       CPDF_ShadingObject* pShadingObj = pPageObj->AsShading();
81       pShadingObj->CalcBoundingBox();
82       break;
83     }
84     case CPDF_PageObject::FORM: {
85       CPDF_FormObject* pFormObj = pPageObj->AsForm();
86       pFormObj->CalcBoundingBox();
87       break;
88     }
89     default: {
90       NOTREACHED();
91       break;
92     }
93   }
94 }
95 
96 }  // namespace
97 
FPDF_CreateNewDocument()98 FPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV FPDF_CreateNewDocument() {
99   auto pDoc = pdfium::MakeUnique<CPDF_Document>(nullptr);
100   pDoc->CreateNewDoc();
101 
102   time_t currentTime;
103   ByteString DateStr;
104   if (FSDK_IsSandBoxPolicyEnabled(FPDF_POLICY_MACHINETIME_ACCESS)) {
105     if (time(&currentTime) != -1) {
106       tm* pTM = localtime(&currentTime);
107       if (pTM) {
108         DateStr = ByteString::Format(
109             "D:%04d%02d%02d%02d%02d%02d", pTM->tm_year + 1900, pTM->tm_mon + 1,
110             pTM->tm_mday, pTM->tm_hour, pTM->tm_min, pTM->tm_sec);
111       }
112     }
113   }
114 
115   CPDF_Dictionary* pInfoDict = pDoc->GetInfo();
116   if (pInfoDict) {
117     if (FSDK_IsSandBoxPolicyEnabled(FPDF_POLICY_MACHINETIME_ACCESS))
118       pInfoDict->SetNewFor<CPDF_String>("CreationDate", DateStr, false);
119     pInfoDict->SetNewFor<CPDF_String>("Creator", L"PDFium");
120   }
121 
122   // Caller takes ownership of pDoc.
123   return FPDFDocumentFromCPDFDocument(pDoc.release());
124 }
125 
FPDFPage_Delete(FPDF_DOCUMENT document,int page_index)126 FPDF_EXPORT void FPDF_CALLCONV FPDFPage_Delete(FPDF_DOCUMENT document,
127                                                int page_index) {
128   if (UnderlyingDocumentType* pDoc = UnderlyingFromFPDFDocument(document))
129     pDoc->DeletePage(page_index);
130 }
131 
FPDFPage_New(FPDF_DOCUMENT document,int page_index,double width,double height)132 FPDF_EXPORT FPDF_PAGE FPDF_CALLCONV FPDFPage_New(FPDF_DOCUMENT document,
133                                                  int page_index,
134                                                  double width,
135                                                  double height) {
136   CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
137   if (!pDoc)
138     return nullptr;
139 
140   page_index = pdfium::clamp(page_index, 0, pDoc->GetPageCount());
141   CPDF_Dictionary* pPageDict = pDoc->CreateNewPage(page_index);
142   if (!pPageDict)
143     return nullptr;
144 
145   CPDF_Array* pMediaBoxArray = pPageDict->SetNewFor<CPDF_Array>("MediaBox");
146   pMediaBoxArray->AddNew<CPDF_Number>(0);
147   pMediaBoxArray->AddNew<CPDF_Number>(0);
148   pMediaBoxArray->AddNew<CPDF_Number>(static_cast<float>(width));
149   pMediaBoxArray->AddNew<CPDF_Number>(static_cast<float>(height));
150   pPageDict->SetNewFor<CPDF_Number>("Rotate", 0);
151   pPageDict->SetNewFor<CPDF_Dictionary>("Resources");
152 
153 #ifdef PDF_ENABLE_XFA
154   auto pXFAPage = pdfium::MakeRetain<CPDFXFA_Page>(
155       static_cast<CPDFXFA_Context*>(document), page_index);
156   pXFAPage->LoadPDFPage(pPageDict);
157   return pXFAPage.Leak();  // Caller takes ownership.
158 #else   // PDF_ENABLE_XFA
159   auto pPage = pdfium::MakeUnique<CPDF_Page>(pDoc, pPageDict, true);
160   pPage->ParseContent();
161   return pPage.release();  // Caller takes ownership.
162 #endif  // PDF_ENABLE_XFA
163 }
164 
FPDFPage_GetRotation(FPDF_PAGE page)165 FPDF_EXPORT int FPDF_CALLCONV FPDFPage_GetRotation(FPDF_PAGE page) {
166   CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
167   return IsPageObject(pPage) ? pPage->GetPageRotation() : -1;
168 }
169 
FPDFPage_InsertObject(FPDF_PAGE page,FPDF_PAGEOBJECT page_obj)170 FPDF_EXPORT void FPDF_CALLCONV FPDFPage_InsertObject(FPDF_PAGE page,
171                                                      FPDF_PAGEOBJECT page_obj) {
172   CPDF_PageObject* pPageObj = CPDFPageObjectFromFPDFPageObject(page_obj);
173   if (!pPageObj)
174     return;
175 
176   std::unique_ptr<CPDF_PageObject> pPageObjHolder(pPageObj);
177   CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
178   if (!IsPageObject(pPage))
179     return;
180   pPageObj->SetDirty(true);
181   pPage->GetPageObjectList()->push_back(std::move(pPageObjHolder));
182   CalcBoundingBox(pPageObj);
183 }
184 
FPDFPage_CountObject(FPDF_PAGE page)185 FPDF_EXPORT int FPDF_CALLCONV FPDFPage_CountObject(FPDF_PAGE page) {
186   return FPDFPage_CountObjects(page);
187 }
188 
FPDFPage_CountObjects(FPDF_PAGE page)189 FPDF_EXPORT int FPDF_CALLCONV FPDFPage_CountObjects(FPDF_PAGE page) {
190   CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
191   if (!IsPageObject(pPage))
192     return -1;
193   return pdfium::CollectionSize<int>(*pPage->GetPageObjectList());
194 }
195 
FPDFPage_GetObject(FPDF_PAGE page,int index)196 FPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV FPDFPage_GetObject(FPDF_PAGE page,
197                                                              int index) {
198   CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
199   if (!IsPageObject(pPage))
200     return nullptr;
201   return pPage->GetPageObjectList()->GetPageObjectByIndex(index);
202 }
203 
FPDFPage_HasTransparency(FPDF_PAGE page)204 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_HasTransparency(FPDF_PAGE page) {
205   CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
206   return pPage && pPage->BackgroundAlphaNeeded();
207 }
208 
FPDFPageObj_Destroy(FPDF_PAGEOBJECT page_obj)209 FPDF_EXPORT void FPDF_CALLCONV FPDFPageObj_Destroy(FPDF_PAGEOBJECT page_obj) {
210   delete CPDFPageObjectFromFPDFPageObject(page_obj);
211 }
212 
213 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDFPageObj_HasTransparency(FPDF_PAGEOBJECT pageObject)214 FPDFPageObj_HasTransparency(FPDF_PAGEOBJECT pageObject) {
215   if (!pageObject)
216     return false;
217 
218   CPDF_PageObject* pPageObj = CPDFPageObjectFromFPDFPageObject(pageObject);
219   int blend_type = pPageObj->m_GeneralState.GetBlendType();
220   if (blend_type != FXDIB_BLEND_NORMAL)
221     return true;
222 
223   CPDF_Dictionary* pSMaskDict =
224       ToDictionary(pPageObj->m_GeneralState.GetSoftMask());
225   if (pSMaskDict)
226     return true;
227 
228   if (pPageObj->m_GeneralState.GetFillAlpha() != 1.0f)
229     return true;
230 
231   if (pPageObj->IsPath() && pPageObj->m_GeneralState.GetStrokeAlpha() != 1.0f) {
232     return true;
233   }
234 
235   if (pPageObj->IsForm()) {
236     const CPDF_Form* pForm = pPageObj->AsForm()->form();
237     if (pForm) {
238       int trans = pForm->m_iTransparency;
239       if ((trans & PDFTRANS_ISOLATED) || (trans & PDFTRANS_GROUP))
240         return true;
241     }
242   }
243 
244   return false;
245 }
246 
FPDFPageObj_GetType(FPDF_PAGEOBJECT pageObject)247 FPDF_EXPORT int FPDF_CALLCONV FPDFPageObj_GetType(FPDF_PAGEOBJECT pageObject) {
248   if (!pageObject)
249     return FPDF_PAGEOBJ_UNKNOWN;
250 
251   CPDF_PageObject* pPageObj = CPDFPageObjectFromFPDFPageObject(pageObject);
252   return pPageObj->GetType();
253 }
254 
FPDFPage_GenerateContent(FPDF_PAGE page)255 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_GenerateContent(FPDF_PAGE page) {
256   CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
257   if (!IsPageObject(pPage))
258     return false;
259 
260   CPDF_PageContentGenerator CG(pPage);
261   CG.GenerateContent();
262   return true;
263 }
264 
265 FPDF_EXPORT void FPDF_CALLCONV
FPDFPageObj_Transform(FPDF_PAGEOBJECT page_object,double a,double b,double c,double d,double e,double f)266 FPDFPageObj_Transform(FPDF_PAGEOBJECT page_object,
267                       double a,
268                       double b,
269                       double c,
270                       double d,
271                       double e,
272                       double f) {
273   CPDF_PageObject* pPageObj = CPDFPageObjectFromFPDFPageObject(page_object);
274   if (!pPageObj)
275     return;
276 
277   CFX_Matrix matrix((float)a, (float)b, (float)c, (float)d, (float)e, (float)f);
278   pPageObj->Transform(matrix);
279 }
280 
281 FPDF_EXPORT void FPDF_CALLCONV
FPDFPageObj_SetBlendMode(FPDF_PAGEOBJECT page_object,FPDF_BYTESTRING blend_mode)282 FPDFPageObj_SetBlendMode(FPDF_PAGEOBJECT page_object,
283                          FPDF_BYTESTRING blend_mode) {
284   CPDF_PageObject* pPageObj = CPDFPageObjectFromFPDFPageObject(page_object);
285   if (!pPageObj)
286     return;
287 
288   pPageObj->m_GeneralState.SetBlendMode(blend_mode);
289   pPageObj->SetDirty(true);
290 }
291 
FPDFPage_TransformAnnots(FPDF_PAGE page,double a,double b,double c,double d,double e,double f)292 FPDF_EXPORT void FPDF_CALLCONV FPDFPage_TransformAnnots(FPDF_PAGE page,
293                                                         double a,
294                                                         double b,
295                                                         double c,
296                                                         double d,
297                                                         double e,
298                                                         double f) {
299   CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
300   if (!pPage)
301     return;
302 
303   CPDF_AnnotList AnnotList(pPage);
304   for (size_t i = 0; i < AnnotList.Count(); ++i) {
305     CPDF_Annot* pAnnot = AnnotList.GetAt(i);
306     CFX_Matrix matrix((float)a, (float)b, (float)c, (float)d, (float)e,
307                       (float)f);
308     CFX_FloatRect rect = matrix.TransformRect(pAnnot->GetRect());
309 
310     CPDF_Dictionary* pAnnotDict = pAnnot->GetAnnotDict();
311     CPDF_Array* pRectArray = pAnnotDict->GetArrayFor("Rect");
312     if (pRectArray)
313       pRectArray->Clear();
314     else
315       pRectArray = pAnnotDict->SetNewFor<CPDF_Array>("Rect");
316 
317     pRectArray->AddNew<CPDF_Number>(rect.left);
318     pRectArray->AddNew<CPDF_Number>(rect.bottom);
319     pRectArray->AddNew<CPDF_Number>(rect.right);
320     pRectArray->AddNew<CPDF_Number>(rect.top);
321 
322     // TODO(unknown): Transform AP's rectangle
323   }
324 }
325 
FPDFPage_SetRotation(FPDF_PAGE page,int rotate)326 FPDF_EXPORT void FPDF_CALLCONV FPDFPage_SetRotation(FPDF_PAGE page,
327                                                     int rotate) {
328   CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
329   if (!IsPageObject(pPage))
330     return;
331 
332   rotate %= 4;
333   pPage->m_pFormDict->SetNewFor<CPDF_Number>("Rotate", rotate * 90);
334 }
335 
FPDFPageObj_SetFillColor(FPDF_PAGEOBJECT page_object,unsigned int R,unsigned int G,unsigned int B,unsigned int A)336 FPDF_BOOL FPDFPageObj_SetFillColor(FPDF_PAGEOBJECT page_object,
337                                    unsigned int R,
338                                    unsigned int G,
339                                    unsigned int B,
340                                    unsigned int A) {
341   if (!page_object || R > 255 || G > 255 || B > 255 || A > 255)
342     return false;
343 
344   float rgb[3] = {R / 255.f, G / 255.f, B / 255.f};
345   auto* pPageObj = CPDFPageObjectFromFPDFPageObject(page_object);
346   pPageObj->m_GeneralState.SetFillAlpha(A / 255.f);
347   pPageObj->m_ColorState.SetFillColor(
348       CPDF_ColorSpace::GetStockCS(PDFCS_DEVICERGB), rgb, 3);
349   pPageObj->SetDirty(true);
350   return true;
351 }
352 
353 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDFPageObj_GetBounds(FPDF_PAGEOBJECT pageObject,float * left,float * bottom,float * right,float * top)354 FPDFPageObj_GetBounds(FPDF_PAGEOBJECT pageObject,
355                       float* left,
356                       float* bottom,
357                       float* right,
358                       float* top) {
359   if (!pageObject)
360     return false;
361 
362   CPDF_PageObject* pPageObj = CPDFPageObjectFromFPDFPageObject(pageObject);
363   CFX_FloatRect bbox = pPageObj->GetRect();
364   *left = bbox.left;
365   *bottom = bbox.bottom;
366   *right = bbox.right;
367   *top = bbox.top;
368   return true;
369 }
370