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 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 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 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(¤tTime) != -1) { 106 tm* pTM = localtime(¤tTime); 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 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 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 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 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 185 FPDF_EXPORT int FPDF_CALLCONV FPDFPage_CountObject(FPDF_PAGE page) { 186 return FPDFPage_CountObjects(page); 187 } 188 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 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 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 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 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 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 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 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 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 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 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 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 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