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/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 
     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 
     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 
     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 
     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 
    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 
    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 
    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 
    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 
    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
    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 
    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 
    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 
    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 
    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