• 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/stl_util.h"
30 
31 #ifdef PDF_ENABLE_XFA
32 #include "fpdfsdk/fpdfxfa/cpdfxfa_context.h"
33 #include "fpdfsdk/fpdfxfa/cpdfxfa_page.h"
34 #endif  // PDF_ENABLE_XFA
35 
36 #if _FX_OS_ == _FX_ANDROID_
37 #include <time.h>
38 #else
39 #include <ctime>
40 #endif
41 
42 namespace {
43 
44 static_assert(FPDF_PAGEOBJ_TEXT == CPDF_PageObject::TEXT,
45               "FPDF_PAGEOBJ_TEXT/CPDF_PageObject::TEXT mismatch");
46 static_assert(FPDF_PAGEOBJ_PATH == CPDF_PageObject::PATH,
47               "FPDF_PAGEOBJ_PATH/CPDF_PageObject::PATH mismatch");
48 static_assert(FPDF_PAGEOBJ_IMAGE == CPDF_PageObject::IMAGE,
49               "FPDF_PAGEOBJ_IMAGE/CPDF_PageObject::IMAGE mismatch");
50 static_assert(FPDF_PAGEOBJ_SHADING == CPDF_PageObject::SHADING,
51               "FPDF_PAGEOBJ_SHADING/CPDF_PageObject::SHADING mismatch");
52 static_assert(FPDF_PAGEOBJ_FORM == CPDF_PageObject::FORM,
53               "FPDF_PAGEOBJ_FORM/CPDF_PageObject::FORM mismatch");
54 
IsPageObject(CPDF_Page * pPage)55 bool IsPageObject(CPDF_Page* pPage) {
56   if (!pPage || !pPage->m_pFormDict || !pPage->m_pFormDict->KeyExist("Type"))
57     return false;
58 
59   CPDF_Object* pObject = pPage->m_pFormDict->GetObjectFor("Type")->GetDirect();
60   return pObject && !pObject->GetString().Compare("Page");
61 }
62 
63 }  // namespace
64 
FPDF_CreateNewDocument()65 DLLEXPORT FPDF_DOCUMENT STDCALL FPDF_CreateNewDocument() {
66   CPDF_Document* pDoc = new CPDF_Document(nullptr);
67   pDoc->CreateNewDoc();
68   time_t currentTime;
69 
70   CFX_ByteString DateStr;
71 
72   if (FSDK_IsSandBoxPolicyEnabled(FPDF_POLICY_MACHINETIME_ACCESS)) {
73     if (-1 != time(&currentTime)) {
74       tm* pTM = localtime(&currentTime);
75       if (pTM) {
76         DateStr.Format("D:%04d%02d%02d%02d%02d%02d", pTM->tm_year + 1900,
77                        pTM->tm_mon + 1, pTM->tm_mday, pTM->tm_hour, pTM->tm_min,
78                        pTM->tm_sec);
79       }
80     }
81   }
82 
83   CPDF_Dictionary* pInfoDict = nullptr;
84   pInfoDict = pDoc->GetInfo();
85   if (pInfoDict) {
86     if (FSDK_IsSandBoxPolicyEnabled(FPDF_POLICY_MACHINETIME_ACCESS))
87       pInfoDict->SetNewFor<CPDF_String>("CreationDate", DateStr, false);
88     pInfoDict->SetNewFor<CPDF_String>("Creator", L"PDFium");
89   }
90 
91   return FPDFDocumentFromCPDFDocument(pDoc);
92 }
93 
FPDFPage_Delete(FPDF_DOCUMENT document,int page_index)94 DLLEXPORT void STDCALL FPDFPage_Delete(FPDF_DOCUMENT document, int page_index) {
95   if (UnderlyingDocumentType* pDoc = UnderlyingFromFPDFDocument(document))
96     pDoc->DeletePage(page_index);
97 }
98 
FPDFPage_New(FPDF_DOCUMENT document,int page_index,double width,double height)99 DLLEXPORT FPDF_PAGE STDCALL FPDFPage_New(FPDF_DOCUMENT document,
100                                          int page_index,
101                                          double width,
102                                          double height) {
103   CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
104   if (!pDoc)
105     return nullptr;
106 
107   page_index = std::min(std::max(page_index, 0), pDoc->GetPageCount());
108   CPDF_Dictionary* pPageDict = pDoc->CreateNewPage(page_index);
109   if (!pPageDict)
110     return nullptr;
111 
112   CPDF_Array* pMediaBoxArray = pPageDict->SetNewFor<CPDF_Array>("MediaBox");
113   pMediaBoxArray->AddNew<CPDF_Number>(0);
114   pMediaBoxArray->AddNew<CPDF_Number>(0);
115   pMediaBoxArray->AddNew<CPDF_Number>(static_cast<FX_FLOAT>(width));
116   pMediaBoxArray->AddNew<CPDF_Number>(static_cast<FX_FLOAT>(height));
117   pPageDict->SetNewFor<CPDF_Number>("Rotate", 0);
118   pPageDict->SetNewFor<CPDF_Dictionary>("Resources");
119 
120 #ifdef PDF_ENABLE_XFA
121   CPDFXFA_Page* pPage =
122       new CPDFXFA_Page(static_cast<CPDFXFA_Context*>(document), page_index);
123   pPage->LoadPDFPage(pPageDict);
124 #else   // PDF_ENABLE_XFA
125   CPDF_Page* pPage = new CPDF_Page(pDoc, pPageDict, true);
126   pPage->ParseContent();
127 #endif  // PDF_ENABLE_XFA
128 
129   return pPage;
130 }
131 
FPDFPage_GetRotation(FPDF_PAGE page)132 DLLEXPORT int STDCALL FPDFPage_GetRotation(FPDF_PAGE page) {
133   CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
134   if (!IsPageObject(pPage))
135     return -1;
136 
137   CPDF_Dictionary* pDict = pPage->m_pFormDict;
138   while (pDict) {
139     if (pDict->KeyExist("Rotate")) {
140       CPDF_Object* pRotateObj = pDict->GetObjectFor("Rotate")->GetDirect();
141       return pRotateObj ? pRotateObj->GetInteger() / 90 : 0;
142     }
143     if (!pDict->KeyExist("Parent"))
144       break;
145 
146     pDict = ToDictionary(pDict->GetObjectFor("Parent")->GetDirect());
147   }
148 
149   return 0;
150 }
151 
FPDFPage_InsertObject(FPDF_PAGE page,FPDF_PAGEOBJECT page_obj)152 DLLEXPORT void STDCALL FPDFPage_InsertObject(FPDF_PAGE page,
153                                              FPDF_PAGEOBJECT page_obj) {
154   CPDF_PageObject* pPageObj = reinterpret_cast<CPDF_PageObject*>(page_obj);
155   if (!pPageObj)
156     return;
157 
158   std::unique_ptr<CPDF_PageObject> pPageObjHolder(pPageObj);
159   CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
160   if (!IsPageObject(pPage))
161     return;
162 
163   pPage->GetPageObjectList()->push_back(std::move(pPageObjHolder));
164   switch (pPageObj->GetType()) {
165     case CPDF_PageObject::TEXT: {
166       break;
167     }
168     case CPDF_PageObject::PATH: {
169       CPDF_PathObject* pPathObj = pPageObj->AsPath();
170       pPathObj->CalcBoundingBox();
171       break;
172     }
173     case CPDF_PageObject::IMAGE: {
174       CPDF_ImageObject* pImageObj = pPageObj->AsImage();
175       pImageObj->CalcBoundingBox();
176       break;
177     }
178     case CPDF_PageObject::SHADING: {
179       CPDF_ShadingObject* pShadingObj = pPageObj->AsShading();
180       pShadingObj->CalcBoundingBox();
181       break;
182     }
183     case CPDF_PageObject::FORM: {
184       CPDF_FormObject* pFormObj = pPageObj->AsForm();
185       pFormObj->CalcBoundingBox();
186       break;
187     }
188     default: {
189       ASSERT(false);
190       break;
191     }
192   }
193 }
194 
FPDFPage_CountObject(FPDF_PAGE page)195 DLLEXPORT int STDCALL FPDFPage_CountObject(FPDF_PAGE page) {
196   CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
197   if (!IsPageObject(pPage))
198     return -1;
199   return pdfium::CollectionSize<int>(*pPage->GetPageObjectList());
200 }
201 
FPDFPage_GetObject(FPDF_PAGE page,int index)202 DLLEXPORT FPDF_PAGEOBJECT STDCALL FPDFPage_GetObject(FPDF_PAGE page,
203                                                      int index) {
204   CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
205   if (!IsPageObject(pPage))
206     return nullptr;
207   return pPage->GetPageObjectList()->GetPageObjectByIndex(index);
208 }
209 
FPDFPage_HasTransparency(FPDF_PAGE page)210 DLLEXPORT FPDF_BOOL STDCALL FPDFPage_HasTransparency(FPDF_PAGE page) {
211   CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
212   return pPage && pPage->BackgroundAlphaNeeded();
213 }
214 
215 DLLEXPORT FPDF_BOOL STDCALL
FPDFPageObj_HasTransparency(FPDF_PAGEOBJECT pageObject)216 FPDFPageObj_HasTransparency(FPDF_PAGEOBJECT pageObject) {
217   if (!pageObject)
218     return false;
219 
220   CPDF_PageObject* pPageObj = reinterpret_cast<CPDF_PageObject*>(pageObject);
221   int blend_type = pPageObj->m_GeneralState.GetBlendType();
222   if (blend_type != FXDIB_BLEND_NORMAL)
223     return true;
224 
225   CPDF_Dictionary* pSMaskDict =
226       ToDictionary(pPageObj->m_GeneralState.GetSoftMask());
227   if (pSMaskDict)
228     return true;
229 
230   if (pPageObj->m_GeneralState.GetFillAlpha() != 1.0f)
231     return true;
232 
233   if (pPageObj->IsPath() && pPageObj->m_GeneralState.GetStrokeAlpha() != 1.0f) {
234     return true;
235   }
236 
237   if (pPageObj->IsForm()) {
238     const CPDF_Form* pForm = pPageObj->AsForm()->form();
239     if (pForm) {
240       int trans = pForm->m_Transparency;
241       if ((trans & PDFTRANS_ISOLATED) || (trans & PDFTRANS_GROUP))
242         return true;
243     }
244   }
245 
246   return false;
247 }
248 
FPDFPage_GenerateContent(FPDF_PAGE page)249 DLLEXPORT FPDF_BOOL STDCALL FPDFPage_GenerateContent(FPDF_PAGE page) {
250   CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
251   if (!IsPageObject(pPage))
252     return false;
253 
254   CPDF_PageContentGenerator CG(pPage);
255   CG.GenerateContent();
256   return true;
257 }
258 
FPDFPageObj_Transform(FPDF_PAGEOBJECT page_object,double a,double b,double c,double d,double e,double f)259 DLLEXPORT void STDCALL FPDFPageObj_Transform(FPDF_PAGEOBJECT page_object,
260                                              double a,
261                                              double b,
262                                              double c,
263                                              double d,
264                                              double e,
265                                              double f) {
266   CPDF_PageObject* pPageObj = reinterpret_cast<CPDF_PageObject*>(page_object);
267   if (!pPageObj)
268     return;
269 
270   CFX_Matrix matrix((FX_FLOAT)a, (FX_FLOAT)b, (FX_FLOAT)c, (FX_FLOAT)d,
271                     (FX_FLOAT)e, (FX_FLOAT)f);
272   pPageObj->Transform(matrix);
273 }
274 
FPDFPage_TransformAnnots(FPDF_PAGE page,double a,double b,double c,double d,double e,double f)275 DLLEXPORT void STDCALL FPDFPage_TransformAnnots(FPDF_PAGE page,
276                                                 double a,
277                                                 double b,
278                                                 double c,
279                                                 double d,
280                                                 double e,
281                                                 double f) {
282   CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
283   if (!pPage)
284     return;
285 
286   CPDF_AnnotList AnnotList(pPage);
287   for (size_t i = 0; i < AnnotList.Count(); ++i) {
288     CPDF_Annot* pAnnot = AnnotList.GetAt(i);
289     CFX_FloatRect rect = pAnnot->GetRect();  // transformAnnots Rectangle
290     CFX_Matrix matrix((FX_FLOAT)a, (FX_FLOAT)b, (FX_FLOAT)c, (FX_FLOAT)d,
291                       (FX_FLOAT)e, (FX_FLOAT)f);
292     matrix.TransformRect(rect);
293 
294     CPDF_Array* pRectArray = pAnnot->GetAnnotDict()->GetArrayFor("Rect");
295     if (!pRectArray)
296       pRectArray = pAnnot->GetAnnotDict()->SetNewFor<CPDF_Array>("Rect");
297 
298     pRectArray->SetNewAt<CPDF_Number>(0, rect.left);
299     pRectArray->SetNewAt<CPDF_Number>(1, rect.bottom);
300     pRectArray->SetNewAt<CPDF_Number>(2, rect.right);
301     pRectArray->SetNewAt<CPDF_Number>(3, rect.top);
302 
303     // TODO(unknown): Transform AP's rectangle
304   }
305 }
306 
FPDFPage_SetRotation(FPDF_PAGE page,int rotate)307 DLLEXPORT void STDCALL FPDFPage_SetRotation(FPDF_PAGE page, int rotate) {
308   CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
309   if (!IsPageObject(pPage))
310     return;
311 
312   CPDF_Dictionary* pDict = pPage->m_pFormDict;
313   rotate %= 4;
314   pDict->SetNewFor<CPDF_Number>("Rotate", rotate * 90);
315 }
316