embedder_test.cpp revision ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4
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
27namespace {
28const char* g_exe_path_ = nullptr;
29}  // namespace
30
31FPDF_BOOL Is_Data_Avail(FX_FILEAVAIL* pThis, size_t offset, size_t size) {
32  return true;
33}
34
35void Add_Segment(FX_DOWNLOADHINTS* pThis, size_t offset, size_t size) {}
36
37EmbedderTest::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
61EmbedderTest::~EmbedderTest() {}
62
63void 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
78void 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
104bool EmbedderTest::CreateEmptyDocument() {
105  document_ = FPDF_CreateNewDocument();
106  if (!document_)
107    return false;
108
109  SetupFormFillEnvironment();
110  return true;
111}
112
113bool 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
184void 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
207void EmbedderTest::DoOpenActions() {
208  FORM_DoDocumentJSAction(form_handle_);
209  FORM_DoDocumentOpenAction(form_handle_);
210}
211
212int EmbedderTest::GetFirstPageNum() {
213  int first_page = FPDFAvail_GetFirstPageNum(document_);
214  (void)FPDFAvail_IsPageAvail(avail_, first_page, &hints_);
215  return first_page;
216}
217
218int 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
226FPDF_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
236FPDF_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
245FPDF_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
257void 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
263FPDF_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
280void EmbedderTest::UnsupportedHandlerTrampoline(UNSUPPORT_INFO* info,
281                                                int type) {
282  EmbedderTest* test = static_cast<EmbedderTest*>(info);
283  test->delegate_->UnsupportedHandler(type);
284}
285
286// static
287int 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
297int 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
305void EmbedderTest::KillTimerTrampoline(FPDF_FORMFILLINFO* info, int id) {
306  EmbedderTest* test = static_cast<EmbedderTest*>(info);
307  return test->delegate_->KillTimer(id);
308}
309
310// static
311FPDF_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.
320int 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