Home | History | Annotate | Download | only in fpdfsdk
      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(&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 
    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