Home | History | Annotate | Download | only in testing
      1 // Copyright 2015 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 #include "testing/embedder_test.h"
      6 
      7 #include <limits.h>
      8 
      9 #include <list>
     10 #include <string>
     11 #include <utility>
     12 #include <vector>
     13 
     14 #include "public/fpdf_dataavail.h"
     15 #include "public/fpdf_edit.h"
     16 #include "public/fpdf_text.h"
     17 #include "public/fpdfview.h"
     18 #include "testing/gmock/include/gmock/gmock.h"
     19 #include "testing/test_support.h"
     20 #include "testing/utils/path_service.h"
     21 
     22 #ifdef PDF_ENABLE_V8
     23 #include "v8/include/v8.h"
     24 #include "v8/include/v8-platform.h"
     25 #endif  // PDF_ENABLE_V8
     26 
     27 namespace {
     28 const char* g_exe_path_ = nullptr;
     29 }  // namespace
     30 
     31 FPDF_BOOL Is_Data_Avail(FX_FILEAVAIL* pThis, size_t offset, size_t size) {
     32   return true;
     33 }
     34 
     35 void Add_Segment(FX_DOWNLOADHINTS* pThis, size_t offset, size_t size) {}
     36 
     37 EmbedderTest::EmbedderTest()
     38     : default_delegate_(new EmbedderTest::Delegate()),
     39       document_(nullptr),
     40       form_handle_(nullptr),
     41       avail_(nullptr),
     42       external_isolate_(nullptr),
     43       loader_(nullptr),
     44       file_length_(0),
     45       file_contents_(nullptr) {
     46   memset(&hints_, 0, sizeof(hints_));
     47   memset(&file_access_, 0, sizeof(file_access_));
     48   memset(&file_avail_, 0, sizeof(file_avail_));
     49   delegate_ = default_delegate_.get();
     50 
     51 #ifdef PDF_ENABLE_V8
     52 #ifdef V8_USE_EXTERNAL_STARTUP_DATA
     53   InitializeV8ForPDFium(g_exe_path_, std::string(), &natives_, &snapshot_,
     54                         &platform_);
     55 #else
     56   InitializeV8ForPDFium(&platform_);
     57 #endif  // V8_USE_EXTERNAL_STARTUP_DATA
     58 #endif  // FPDF_ENABLE_V8
     59 }
     60 
     61 EmbedderTest::~EmbedderTest() {}
     62 
     63 void EmbedderTest::SetUp() {
     64   FPDF_LIBRARY_CONFIG config;
     65   config.version = 2;
     66   config.m_pUserFontPaths = nullptr;
     67   config.m_v8EmbedderSlot = 0;
     68   config.m_pIsolate = external_isolate_;
     69   FPDF_InitLibraryWithConfig(&config);
     70 
     71   UNSUPPORT_INFO* info = static_cast<UNSUPPORT_INFO*>(this);
     72   memset(info, 0, sizeof(UNSUPPORT_INFO));
     73   info->version = 1;
     74   info->FSDK_UnSupport_Handler = UnsupportedHandlerTrampoline;
     75   FSDK_SetUnSpObjProcessHandler(info);
     76 }
     77 
     78 void EmbedderTest::TearDown() {
     79   if (document_) {
     80     FORM_DoDocumentAAction(form_handle_, FPDFDOC_AACTION_WC);
     81 #ifdef PDF_ENABLE_XFA
     82     // Note: The shut down order here is the reverse of the non-XFA branch
     83     // order. Need to work out if this is required, and if it is, the lifetimes
     84     // of objects owned by |doc| that |form| reference.
     85     FPDF_CloseDocument(document_);
     86     FPDFDOC_ExitFormFillEnvironment(form_handle_);
     87 #else   // PDF_ENABLE_XFA
     88     FPDFDOC_ExitFormFillEnvironment(form_handle_);
     89     FPDF_CloseDocument(document_);
     90 #endif  // PDF_ENABLE_XFA
     91   }
     92 
     93   FPDFAvail_Destroy(avail_);
     94   FPDF_DestroyLibrary();
     95 
     96 #ifdef PDF_ENABLE_V8
     97   v8::V8::ShutdownPlatform();
     98   delete platform_;
     99 #endif  // PDF_ENABLE_V8
    100 
    101   delete loader_;
    102 }
    103 
    104 bool EmbedderTest::CreateEmptyDocument() {
    105   document_ = FPDF_CreateNewDocument();
    106   if (!document_)
    107     return false;
    108 
    109   SetupFormFillEnvironment();
    110   return true;
    111 }
    112 
    113 bool EmbedderTest::OpenDocument(const std::string& filename,
    114                                 bool must_linearize) {
    115   std::string file_path;
    116   if (!PathService::GetTestFilePath(filename, &file_path))
    117     return false;
    118   file_contents_ = GetFileContents(file_path.c_str(), &file_length_);
    119   if (!file_contents_)
    120     return false;
    121 
    122   loader_ = new TestLoader(file_contents_.get(), file_length_);
    123   file_access_.m_FileLen = static_cast<unsigned long>(file_length_);
    124   file_access_.m_GetBlock = TestLoader::GetBlock;
    125   file_access_.m_Param = loader_;
    126 
    127   file_avail_.version = 1;
    128   file_avail_.IsDataAvail = Is_Data_Avail;
    129 
    130   hints_.version = 1;
    131   hints_.AddSegment = Add_Segment;
    132 
    133   avail_ = FPDFAvail_Create(&file_avail_, &file_access_);
    134 
    135   if (FPDFAvail_IsLinearized(avail_) == PDF_LINEARIZED) {
    136     document_ = FPDFAvail_GetDocument(avail_, nullptr);
    137     if (!document_) {
    138       return false;
    139     }
    140     int32_t nRet = PDF_DATA_NOTAVAIL;
    141     while (nRet == PDF_DATA_NOTAVAIL) {
    142       nRet = FPDFAvail_IsDocAvail(avail_, &hints_);
    143     }
    144     if (nRet == PDF_DATA_ERROR) {
    145       return false;
    146     }
    147     nRet = FPDFAvail_IsFormAvail(avail_, &hints_);
    148     if (nRet == PDF_FORM_ERROR || nRet == PDF_FORM_NOTAVAIL) {
    149       return false;
    150     }
    151     int page_count = FPDF_GetPageCount(document_);
    152     for (int i = 0; i < page_count; ++i) {
    153       nRet = PDF_DATA_NOTAVAIL;
    154       while (nRet == PDF_DATA_NOTAVAIL) {
    155         nRet = FPDFAvail_IsPageAvail(avail_, i, &hints_);
    156       }
    157       if (nRet == PDF_DATA_ERROR) {
    158         return false;
    159       }
    160     }
    161   } else {
    162     if (must_linearize) {
    163       return false;
    164     }
    165     document_ = FPDF_LoadCustomDocument(&file_access_, nullptr);
    166     if (!document_) {
    167       return false;
    168     }
    169   }
    170 
    171 #ifdef PDF_ENABLE_XFA
    172   int docType = DOCTYPE_PDF;
    173   if (FPDF_HasXFAField(document_, &docType)) {
    174     if (docType != DOCTYPE_PDF)
    175       (void)FPDF_LoadXFA(document_);
    176   }
    177 #endif  // PDF_ENABLE_XFA
    178 
    179   (void)FPDF_GetDocPermissions(document_);
    180   SetupFormFillEnvironment();
    181   return true;
    182 }
    183 
    184 void EmbedderTest::SetupFormFillEnvironment() {
    185   IPDF_JSPLATFORM* platform = static_cast<IPDF_JSPLATFORM*>(this);
    186   memset(platform, 0, sizeof(IPDF_JSPLATFORM));
    187   platform->version = 2;
    188   platform->app_alert = AlertTrampoline;
    189 
    190   FPDF_FORMFILLINFO* formfillinfo = static_cast<FPDF_FORMFILLINFO*>(this);
    191   memset(formfillinfo, 0, sizeof(FPDF_FORMFILLINFO));
    192 #ifdef PDF_ENABLE_XFA
    193   formfillinfo->version = 2;
    194 #else   // PDF_ENABLE_XFA
    195   formfillinfo->version = 1;
    196 #endif  // PDF_ENABLE_XFA
    197   formfillinfo->FFI_SetTimer = SetTimerTrampoline;
    198   formfillinfo->FFI_KillTimer = KillTimerTrampoline;
    199   formfillinfo->FFI_GetPage = GetPageTrampoline;
    200   formfillinfo->m_pJsPlatform = platform;
    201 
    202   form_handle_ = FPDFDOC_InitFormFillEnvironment(document_, formfillinfo);
    203   FPDF_SetFormFieldHighlightColor(form_handle_, 0, 0xFFE4DD);
    204   FPDF_SetFormFieldHighlightAlpha(form_handle_, 100);
    205 }
    206 
    207 void EmbedderTest::DoOpenActions() {
    208   FORM_DoDocumentJSAction(form_handle_);
    209   FORM_DoDocumentOpenAction(form_handle_);
    210 }
    211 
    212 int EmbedderTest::GetFirstPageNum() {
    213   int first_page = FPDFAvail_GetFirstPageNum(document_);
    214   (void)FPDFAvail_IsPageAvail(avail_, first_page, &hints_);
    215   return first_page;
    216 }
    217 
    218 int EmbedderTest::GetPageCount() {
    219   int page_count = FPDF_GetPageCount(document_);
    220   for (int i = 0; i < page_count; ++i) {
    221     (void)FPDFAvail_IsPageAvail(avail_, i, &hints_);
    222   }
    223   return page_count;
    224 }
    225 
    226 FPDF_PAGE EmbedderTest::LoadPage(int page_number) {
    227   FPDF_PAGE page = FPDF_LoadPage(document_, page_number);
    228   if (!page) {
    229     return nullptr;
    230   }
    231   FORM_OnAfterLoadPage(page, form_handle_);
    232   FORM_DoPageAAction(page, form_handle_, FPDFPAGE_AACTION_OPEN);
    233   return page;
    234 }
    235 
    236 FPDF_PAGE EmbedderTest::LoadAndCachePage(int page_number) {
    237   FPDF_PAGE page = delegate_->GetPage(form_handle_, document_, page_number);
    238   if (!page) {
    239     return nullptr;
    240   }
    241   FORM_DoPageAAction(page, form_handle_, FPDFPAGE_AACTION_OPEN);
    242   return page;
    243 }
    244 
    245 FPDF_BITMAP EmbedderTest::RenderPage(FPDF_PAGE page) {
    246   int width = static_cast<int>(FPDF_GetPageWidth(page));
    247   int height = static_cast<int>(FPDF_GetPageHeight(page));
    248   int alpha = FPDFPage_HasTransparency(page) ? 1 : 0;
    249   FPDF_BITMAP bitmap = FPDFBitmap_Create(width, height, alpha);
    250   FPDF_DWORD fill_color = alpha ? 0x00000000 : 0xFFFFFFFF;
    251   FPDFBitmap_FillRect(bitmap, 0, 0, width, height, fill_color);
    252   FPDF_RenderPageBitmap(bitmap, page, 0, 0, width, height, 0, 0);
    253   FPDF_FFLDraw(form_handle_, bitmap, page, 0, 0, width, height, 0, 0);
    254   return bitmap;
    255 }
    256 
    257 void EmbedderTest::UnloadPage(FPDF_PAGE page) {
    258   FORM_DoPageAAction(page, form_handle_, FPDFPAGE_AACTION_CLOSE);
    259   FORM_OnBeforeClosePage(page, form_handle_);
    260   FPDF_ClosePage(page);
    261 }
    262 
    263 FPDF_PAGE EmbedderTest::Delegate::GetPage(FPDF_FORMHANDLE form_handle,
    264                                           FPDF_DOCUMENT document,
    265                                           int page_index) {
    266   auto it = m_pageMap.find(page_index);
    267   if (it != m_pageMap.end()) {
    268     return it->second;
    269   }
    270   FPDF_PAGE page = FPDF_LoadPage(document, page_index);
    271   if (!page) {
    272     return nullptr;
    273   }
    274   m_pageMap[page_index] = page;
    275   FORM_OnAfterLoadPage(page, form_handle);
    276   return page;
    277 }
    278 
    279 // static
    280 void EmbedderTest::UnsupportedHandlerTrampoline(UNSUPPORT_INFO* info,
    281                                                 int type) {
    282   EmbedderTest* test = static_cast<EmbedderTest*>(info);
    283   test->delegate_->UnsupportedHandler(type);
    284 }
    285 
    286 // static
    287 int EmbedderTest::AlertTrampoline(IPDF_JSPLATFORM* platform,
    288                                   FPDF_WIDESTRING message,
    289                                   FPDF_WIDESTRING title,
    290                                   int type,
    291                                   int icon) {
    292   EmbedderTest* test = static_cast<EmbedderTest*>(platform);
    293   return test->delegate_->Alert(message, title, type, icon);
    294 }
    295 
    296 // static
    297 int EmbedderTest::SetTimerTrampoline(FPDF_FORMFILLINFO* info,
    298                                      int msecs,
    299                                      TimerCallback fn) {
    300   EmbedderTest* test = static_cast<EmbedderTest*>(info);
    301   return test->delegate_->SetTimer(msecs, fn);
    302 }
    303 
    304 // static
    305 void EmbedderTest::KillTimerTrampoline(FPDF_FORMFILLINFO* info, int id) {
    306   EmbedderTest* test = static_cast<EmbedderTest*>(info);
    307   return test->delegate_->KillTimer(id);
    308 }
    309 
    310 // static
    311 FPDF_PAGE EmbedderTest::GetPageTrampoline(FPDF_FORMFILLINFO* info,
    312                                           FPDF_DOCUMENT document,
    313                                           int page_index) {
    314   EmbedderTest* test = static_cast<EmbedderTest*>(info);
    315   return test->delegate_->GetPage(test->form_handle(), document, page_index);
    316 }
    317 
    318 // Can't use gtest-provided main since we need to stash the path to the
    319 // executable in order to find the external V8 binary data files.
    320 int main(int argc, char** argv) {
    321   g_exe_path_ = argv[0];
    322   testing::InitGoogleTest(&argc, argv);
    323   testing::InitGoogleMock(&argc, argv);
    324   return RUN_ALL_TESTS();
    325 }
    326