• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2015 The PDFium Authors
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 <algorithm>
8 #include <memory>
9 #include <string>
10 #include <utility>
11 #include <vector>
12 
13 #include "core/fdrm/fx_crypt.h"
14 #include "public/cpp/fpdf_scopers.h"
15 #include "public/fpdf_dataavail.h"
16 #include "public/fpdf_edit.h"
17 #include "public/fpdf_text.h"
18 #include "public/fpdfview.h"
19 #include "testing/embedder_test_environment.h"
20 #include "testing/gmock/include/gmock/gmock.h"
21 #include "testing/test_loader.h"
22 #include "testing/utils/bitmap_saver.h"
23 #include "testing/utils/file_util.h"
24 #include "testing/utils/hash.h"
25 #include "testing/utils/path_service.h"
26 #include "third_party/base/check.h"
27 #include "third_party/base/containers/contains.h"
28 #include "third_party/base/notreached.h"
29 #include "third_party/base/numerics/safe_conversions.h"
30 
31 namespace {
32 
GetBitmapBytesPerPixel(FPDF_BITMAP bitmap)33 int GetBitmapBytesPerPixel(FPDF_BITMAP bitmap) {
34   return EmbedderTest::BytesPerPixelForFormat(FPDFBitmap_GetFormat(bitmap));
35 }
36 
37 #if BUILDFLAG(IS_WIN)
GetRecordProc(HDC hdc,HANDLETABLE * handle_table,const ENHMETARECORD * record,int objects_count,LPARAM param)38 int CALLBACK GetRecordProc(HDC hdc,
39                            HANDLETABLE* handle_table,
40                            const ENHMETARECORD* record,
41                            int objects_count,
42                            LPARAM param) {
43   auto& records = *reinterpret_cast<std::vector<const ENHMETARECORD*>*>(param);
44   records.push_back(record);
45   return 1;
46 }
47 #endif  // BUILDFLAG(IS_WIN)
48 
49 // These "jump" into the delegate to do actual testing.
UnsupportedHandlerTrampoline(UNSUPPORT_INFO * info,int type)50 void UnsupportedHandlerTrampoline(UNSUPPORT_INFO* info, int type) {
51   auto* delegate = static_cast<EmbedderTest*>(info)->GetDelegate();
52   delegate->UnsupportedHandler(type);
53 }
54 
AlertTrampoline(IPDF_JSPLATFORM * platform,FPDF_WIDESTRING message,FPDF_WIDESTRING title,int type,int icon)55 int AlertTrampoline(IPDF_JSPLATFORM* platform,
56                     FPDF_WIDESTRING message,
57                     FPDF_WIDESTRING title,
58                     int type,
59                     int icon) {
60   auto* delegate = static_cast<EmbedderTest*>(platform)->GetDelegate();
61   return delegate->Alert(message, title, type, icon);
62 }
63 
SetTimerTrampoline(FPDF_FORMFILLINFO * info,int msecs,TimerCallback fn)64 int SetTimerTrampoline(FPDF_FORMFILLINFO* info, int msecs, TimerCallback fn) {
65   auto* delegate = static_cast<EmbedderTest*>(info)->GetDelegate();
66   return delegate->SetTimer(msecs, fn);
67 }
68 
KillTimerTrampoline(FPDF_FORMFILLINFO * info,int id)69 void KillTimerTrampoline(FPDF_FORMFILLINFO* info, int id) {
70   auto* delegate = static_cast<EmbedderTest*>(info)->GetDelegate();
71   return delegate->KillTimer(id);
72 }
73 
GetPageTrampoline(FPDF_FORMFILLINFO * info,FPDF_DOCUMENT document,int page_index)74 FPDF_PAGE GetPageTrampoline(FPDF_FORMFILLINFO* info,
75                             FPDF_DOCUMENT document,
76                             int page_index) {
77   auto* delegate = static_cast<EmbedderTest*>(info)->GetDelegate();
78   return delegate->GetPage(info, document, page_index);
79 }
80 
DoURIActionTrampoline(FPDF_FORMFILLINFO * info,FPDF_BYTESTRING uri)81 void DoURIActionTrampoline(FPDF_FORMFILLINFO* info, FPDF_BYTESTRING uri) {
82   auto* delegate = static_cast<EmbedderTest*>(info)->GetDelegate();
83   return delegate->DoURIAction(uri);
84 }
85 
DoGoToActionTrampoline(FPDF_FORMFILLINFO * info,int page_index,int zoom_mode,float * pos_array,int array_size)86 void DoGoToActionTrampoline(FPDF_FORMFILLINFO* info,
87                             int page_index,
88                             int zoom_mode,
89                             float* pos_array,
90                             int array_size) {
91   auto* delegate = static_cast<EmbedderTest*>(info)->GetDelegate();
92   return delegate->DoGoToAction(info, page_index, zoom_mode, pos_array,
93                                 array_size);
94 }
95 
OnFocusChangeTrampoline(FPDF_FORMFILLINFO * info,FPDF_ANNOTATION annot,int page_index)96 void OnFocusChangeTrampoline(FPDF_FORMFILLINFO* info,
97                              FPDF_ANNOTATION annot,
98                              int page_index) {
99   auto* delegate = static_cast<EmbedderTest*>(info)->GetDelegate();
100   return delegate->OnFocusChange(info, annot, page_index);
101 }
102 
DoURIActionWithKeyboardModifierTrampoline(FPDF_FORMFILLINFO * info,FPDF_BYTESTRING uri,int modifiers)103 void DoURIActionWithKeyboardModifierTrampoline(FPDF_FORMFILLINFO* info,
104                                                FPDF_BYTESTRING uri,
105                                                int modifiers) {
106   auto* delegate = static_cast<EmbedderTest*>(info)->GetDelegate();
107   return delegate->DoURIActionWithKeyboardModifier(info, uri, modifiers);
108 }
109 
110 // These do nothing (but must return a reasonable default value).
InvalidateStub(FPDF_FORMFILLINFO * pThis,FPDF_PAGE page,double left,double top,double right,double bottom)111 void InvalidateStub(FPDF_FORMFILLINFO* pThis,
112                     FPDF_PAGE page,
113                     double left,
114                     double top,
115                     double right,
116                     double bottom) {}
117 
OutputSelectedRectStub(FPDF_FORMFILLINFO * pThis,FPDF_PAGE page,double left,double top,double right,double bottom)118 void OutputSelectedRectStub(FPDF_FORMFILLINFO* pThis,
119                             FPDF_PAGE page,
120                             double left,
121                             double top,
122                             double right,
123                             double bottom) {}
124 
SetCursorStub(FPDF_FORMFILLINFO * pThis,int nCursorType)125 void SetCursorStub(FPDF_FORMFILLINFO* pThis, int nCursorType) {}
126 
GetLocalTimeStub(FPDF_FORMFILLINFO * pThis)127 FPDF_SYSTEMTIME GetLocalTimeStub(FPDF_FORMFILLINFO* pThis) {
128   return {122, 11, 6, 28, 12, 59, 59, 500};
129 }
130 
OnChangeStub(FPDF_FORMFILLINFO * pThis)131 void OnChangeStub(FPDF_FORMFILLINFO* pThis) {}
132 
GetCurrentPageStub(FPDF_FORMFILLINFO * pThis,FPDF_DOCUMENT document)133 FPDF_PAGE GetCurrentPageStub(FPDF_FORMFILLINFO* pThis, FPDF_DOCUMENT document) {
134   return GetPageTrampoline(pThis, document, 0);
135 }
136 
GetRotationStub(FPDF_FORMFILLINFO * pThis,FPDF_PAGE page)137 int GetRotationStub(FPDF_FORMFILLINFO* pThis, FPDF_PAGE page) {
138   return 0;
139 }
140 
ExecuteNamedActionStub(FPDF_FORMFILLINFO * pThis,FPDF_BYTESTRING name)141 void ExecuteNamedActionStub(FPDF_FORMFILLINFO* pThis, FPDF_BYTESTRING name) {}
142 
SetTextFieldFocusStub(FPDF_FORMFILLINFO * pThis,FPDF_WIDESTRING value,FPDF_DWORD valueLen,FPDF_BOOL is_focus)143 void SetTextFieldFocusStub(FPDF_FORMFILLINFO* pThis,
144                            FPDF_WIDESTRING value,
145                            FPDF_DWORD valueLen,
146                            FPDF_BOOL is_focus) {}
147 
148 #ifdef PDF_ENABLE_XFA
DisplayCaretStub(FPDF_FORMFILLINFO * pThis,FPDF_PAGE page,FPDF_BOOL bVisible,double left,double top,double right,double bottom)149 void DisplayCaretStub(FPDF_FORMFILLINFO* pThis,
150                       FPDF_PAGE page,
151                       FPDF_BOOL bVisible,
152                       double left,
153                       double top,
154                       double right,
155                       double bottom) {}
156 
GetCurrentPageIndexStub(FPDF_FORMFILLINFO * pThis,FPDF_DOCUMENT document)157 int GetCurrentPageIndexStub(FPDF_FORMFILLINFO* pThis, FPDF_DOCUMENT document) {
158   return 0;
159 }
160 
SetCurrentPageStub(FPDF_FORMFILLINFO * pThis,FPDF_DOCUMENT document,int iCurPage)161 void SetCurrentPageStub(FPDF_FORMFILLINFO* pThis,
162                         FPDF_DOCUMENT document,
163                         int iCurPage) {}
164 
GotoURLStub(FPDF_FORMFILLINFO * pThis,FPDF_DOCUMENT document,FPDF_WIDESTRING wsURL)165 void GotoURLStub(FPDF_FORMFILLINFO* pThis,
166                  FPDF_DOCUMENT document,
167                  FPDF_WIDESTRING wsURL) {}
168 
GetPageViewRectStub(FPDF_FORMFILLINFO * pThis,FPDF_PAGE page,double * left,double * top,double * right,double * bottom)169 void GetPageViewRectStub(FPDF_FORMFILLINFO* pThis,
170                          FPDF_PAGE page,
171                          double* left,
172                          double* top,
173                          double* right,
174                          double* bottom) {
175   *left = 0.0;
176   *top = 0.0;
177   *right = 512.0;
178   *bottom = 512.0;
179 }
180 
PageEventStub(FPDF_FORMFILLINFO * pThis,int page_count,FPDF_DWORD event_type)181 void PageEventStub(FPDF_FORMFILLINFO* pThis,
182                    int page_count,
183                    FPDF_DWORD event_type) {}
184 
PopupMenuStub(FPDF_FORMFILLINFO * pThis,FPDF_PAGE page,FPDF_WIDGET hWidget,int menuFlag,float x,float y)185 FPDF_BOOL PopupMenuStub(FPDF_FORMFILLINFO* pThis,
186                         FPDF_PAGE page,
187                         FPDF_WIDGET hWidget,
188                         int menuFlag,
189                         float x,
190                         float y) {
191   return true;
192 }
193 
OpenFileStub(FPDF_FORMFILLINFO * pThis,int fileFlag,FPDF_WIDESTRING wsURL,const char * mode)194 FPDF_FILEHANDLER* OpenFileStub(FPDF_FORMFILLINFO* pThis,
195                                int fileFlag,
196                                FPDF_WIDESTRING wsURL,
197                                const char* mode) {
198   return nullptr;
199 }
200 
EmailToStub(FPDF_FORMFILLINFO * pThis,FPDF_FILEHANDLER * fileHandler,FPDF_WIDESTRING pTo,FPDF_WIDESTRING pSubject,FPDF_WIDESTRING pCC,FPDF_WIDESTRING pBcc,FPDF_WIDESTRING pMsg)201 void EmailToStub(FPDF_FORMFILLINFO* pThis,
202                  FPDF_FILEHANDLER* fileHandler,
203                  FPDF_WIDESTRING pTo,
204                  FPDF_WIDESTRING pSubject,
205                  FPDF_WIDESTRING pCC,
206                  FPDF_WIDESTRING pBcc,
207                  FPDF_WIDESTRING pMsg) {}
208 
UploadToStub(FPDF_FORMFILLINFO * pThis,FPDF_FILEHANDLER * fileHandler,int fileFlag,FPDF_WIDESTRING uploadTo)209 void UploadToStub(FPDF_FORMFILLINFO* pThis,
210                   FPDF_FILEHANDLER* fileHandler,
211                   int fileFlag,
212                   FPDF_WIDESTRING uploadTo) {}
213 
GetPlatformStub(FPDF_FORMFILLINFO * pThis,void * platform,int length)214 int GetPlatformStub(FPDF_FORMFILLINFO* pThis, void* platform, int length) {
215   return 0;
216 }
217 
GetLanguageStub(FPDF_FORMFILLINFO * pThis,void * language,int length)218 int GetLanguageStub(FPDF_FORMFILLINFO* pThis, void* language, int length) {
219   return 0;
220 }
221 
DownloadFromURLStub(FPDF_FORMFILLINFO * pThis,FPDF_WIDESTRING URL)222 FPDF_FILEHANDLER* DownloadFromURLStub(FPDF_FORMFILLINFO* pThis,
223                                       FPDF_WIDESTRING URL) {
224   static const char kString[] = "<body>secrets</body>";
225   static FPDF_FILEHANDLER kFakeFileHandler = {
226       nullptr,
227       [](void*) -> void {},
228       [](void*) -> FPDF_DWORD { return sizeof(kString); },
229       [](void*, FPDF_DWORD off, void* buffer, FPDF_DWORD size) -> FPDF_RESULT {
230         memcpy(buffer, kString, std::min<size_t>(size, sizeof(kString)));
231         return 0;
232       },
233       [](void*, FPDF_DWORD, const void*, FPDF_DWORD) -> FPDF_RESULT {
234         return -1;
235       },
236       [](void*) -> FPDF_RESULT { return 0; },
237       [](void*, FPDF_DWORD) -> FPDF_RESULT { return 0; }};
238   return &kFakeFileHandler;
239 }
240 
PostRequestURLStub(FPDF_FORMFILLINFO * pThis,FPDF_WIDESTRING wsURL,FPDF_WIDESTRING wsData,FPDF_WIDESTRING wsContentType,FPDF_WIDESTRING wsEncode,FPDF_WIDESTRING wsHeader,FPDF_BSTR * response)241 FPDF_BOOL PostRequestURLStub(FPDF_FORMFILLINFO* pThis,
242                              FPDF_WIDESTRING wsURL,
243                              FPDF_WIDESTRING wsData,
244                              FPDF_WIDESTRING wsContentType,
245                              FPDF_WIDESTRING wsEncode,
246                              FPDF_WIDESTRING wsHeader,
247                              FPDF_BSTR* response) {
248   const char kString[] = "p\0o\0s\0t\0e\0d\0";
249   FPDF_BStr_Set(response, kString, sizeof(kString) - 1);
250   return true;
251 }
252 
PutRequestURLStub(FPDF_FORMFILLINFO * pThis,FPDF_WIDESTRING wsURL,FPDF_WIDESTRING wsData,FPDF_WIDESTRING wsEncode)253 FPDF_BOOL PutRequestURLStub(FPDF_FORMFILLINFO* pThis,
254                             FPDF_WIDESTRING wsURL,
255                             FPDF_WIDESTRING wsData,
256                             FPDF_WIDESTRING wsEncode) {
257   return true;
258 }
259 #endif  // PDF_ENABLE_XFA
260 
261 }  // namespace
262 
EmbedderTest()263 EmbedderTest::EmbedderTest()
264     : default_delegate_(std::make_unique<EmbedderTest::Delegate>()),
265       delegate_(default_delegate_.get()) {
266   FPDF_FILEWRITE::version = 1;
267   FPDF_FILEWRITE::WriteBlock = WriteBlockCallback;
268 }
269 
270 EmbedderTest::~EmbedderTest() = default;
271 
SetUp()272 void EmbedderTest::SetUp() {
273   UNSUPPORT_INFO* info = static_cast<UNSUPPORT_INFO*>(this);
274   memset(info, 0, sizeof(UNSUPPORT_INFO));
275   info->version = 1;
276   info->FSDK_UnSupport_Handler = UnsupportedHandlerTrampoline;
277   FSDK_SetUnSpObjProcessHandler(info);
278 }
279 
TearDown()280 void EmbedderTest::TearDown() {
281   // Use an EXPECT_EQ() here and continue to let TearDown() finish as cleanly as
282   // possible. This can fail when an DCHECK test fails in a test case.
283   EXPECT_EQ(0U, page_map_.size());
284   EXPECT_EQ(0U, saved_page_map_.size());
285   if (document())
286     CloseDocument();
287 }
288 
CreateEmptyDocument()289 void EmbedderTest::CreateEmptyDocument() {
290   CreateEmptyDocumentWithoutFormFillEnvironment();
291   form_handle_.reset(SetupFormFillEnvironment(
292       document(), JavaScriptOption::kEnableJavaScript));
293 }
294 
CreateEmptyDocumentWithoutFormFillEnvironment()295 void EmbedderTest::CreateEmptyDocumentWithoutFormFillEnvironment() {
296   document_.reset(FPDF_CreateNewDocument());
297   DCHECK(document_);
298 }
299 
OpenDocument(const std::string & filename)300 bool EmbedderTest::OpenDocument(const std::string& filename) {
301   return OpenDocumentWithOptions(filename, nullptr,
302                                  LinearizeOption::kDefaultLinearize,
303                                  JavaScriptOption::kEnableJavaScript);
304 }
305 
OpenDocumentLinearized(const std::string & filename)306 bool EmbedderTest::OpenDocumentLinearized(const std::string& filename) {
307   return OpenDocumentWithOptions(filename, nullptr,
308                                  LinearizeOption::kMustLinearize,
309                                  JavaScriptOption::kEnableJavaScript);
310 }
311 
OpenDocumentWithPassword(const std::string & filename,const char * password)312 bool EmbedderTest::OpenDocumentWithPassword(const std::string& filename,
313                                             const char* password) {
314   return OpenDocumentWithOptions(filename, password,
315                                  LinearizeOption::kDefaultLinearize,
316                                  JavaScriptOption::kEnableJavaScript);
317 }
318 
OpenDocumentWithoutJavaScript(const std::string & filename)319 bool EmbedderTest::OpenDocumentWithoutJavaScript(const std::string& filename) {
320   return OpenDocumentWithOptions(filename, nullptr,
321                                  LinearizeOption::kDefaultLinearize,
322                                  JavaScriptOption::kDisableJavaScript);
323 }
324 
OpenDocumentWithOptions(const std::string & filename,const char * password,LinearizeOption linearize_option,JavaScriptOption javascript_option)325 bool EmbedderTest::OpenDocumentWithOptions(const std::string& filename,
326                                            const char* password,
327                                            LinearizeOption linearize_option,
328                                            JavaScriptOption javascript_option) {
329   std::string file_path;
330   if (!PathService::GetTestFilePath(filename, &file_path))
331     return false;
332 
333   file_contents_ = GetFileContents(file_path.c_str(), &file_length_);
334   if (!file_contents_)
335     return false;
336 
337   EXPECT_TRUE(!loader_);
338   loader_ = std::make_unique<TestLoader>(
339       pdfium::make_span(file_contents_.get(), file_length_));
340 
341   memset(&file_access_, 0, sizeof(file_access_));
342   file_access_.m_FileLen = static_cast<unsigned long>(file_length_);
343   file_access_.m_GetBlock = TestLoader::GetBlock;
344   file_access_.m_Param = loader_.get();
345 
346   fake_file_access_ = std::make_unique<FakeFileAccess>(&file_access_);
347   return OpenDocumentHelper(password, linearize_option, javascript_option,
348                             fake_file_access_.get(), &document_, &avail_,
349                             &form_handle_);
350 }
351 
OpenDocumentHelper(const char * password,LinearizeOption linearize_option,JavaScriptOption javascript_option,FakeFileAccess * network_simulator,ScopedFPDFDocument * document,ScopedFPDFAvail * avail,ScopedFPDFFormHandle * form_handle)352 bool EmbedderTest::OpenDocumentHelper(const char* password,
353                                       LinearizeOption linearize_option,
354                                       JavaScriptOption javascript_option,
355                                       FakeFileAccess* network_simulator,
356                                       ScopedFPDFDocument* document,
357                                       ScopedFPDFAvail* avail,
358                                       ScopedFPDFFormHandle* form_handle) {
359   network_simulator->AddSegment(0, 1024);
360   network_simulator->SetRequestedDataAvailable();
361   avail->reset(FPDFAvail_Create(network_simulator->GetFileAvail(),
362                                 network_simulator->GetFileAccess()));
363   FPDF_AVAIL avail_ptr = avail->get();
364   FPDF_DOCUMENT document_ptr = nullptr;
365   if (FPDFAvail_IsLinearized(avail_ptr) == PDF_LINEARIZED) {
366     int32_t nRet = PDF_DATA_NOTAVAIL;
367     while (nRet == PDF_DATA_NOTAVAIL) {
368       network_simulator->SetRequestedDataAvailable();
369       nRet = FPDFAvail_IsDocAvail(avail_ptr,
370                                   network_simulator->GetDownloadHints());
371     }
372     if (nRet == PDF_DATA_ERROR)
373       return false;
374 
375     document->reset(FPDFAvail_GetDocument(avail_ptr, password));
376     document_ptr = document->get();
377     if (!document_ptr)
378       return false;
379 
380     nRet = PDF_DATA_NOTAVAIL;
381     while (nRet == PDF_DATA_NOTAVAIL) {
382       network_simulator->SetRequestedDataAvailable();
383       nRet = FPDFAvail_IsFormAvail(avail_ptr,
384                                    network_simulator->GetDownloadHints());
385     }
386     if (nRet == PDF_FORM_ERROR)
387       return false;
388 
389     int page_count = FPDF_GetPageCount(document_ptr);
390     for (int i = 0; i < page_count; ++i) {
391       nRet = PDF_DATA_NOTAVAIL;
392       while (nRet == PDF_DATA_NOTAVAIL) {
393         network_simulator->SetRequestedDataAvailable();
394         nRet = FPDFAvail_IsPageAvail(avail_ptr, i,
395                                      network_simulator->GetDownloadHints());
396       }
397       if (nRet == PDF_DATA_ERROR)
398         return false;
399     }
400   } else {
401     if (linearize_option == LinearizeOption::kMustLinearize)
402       return false;
403     network_simulator->SetWholeFileAvailable();
404     document->reset(
405         FPDF_LoadCustomDocument(network_simulator->GetFileAccess(), password));
406     document_ptr = document->get();
407     if (!document_ptr)
408       return false;
409   }
410   form_handle->reset(SetupFormFillEnvironment(document_ptr, javascript_option));
411 
412   int doc_type = FPDF_GetFormType(document_ptr);
413   if (doc_type == FORMTYPE_XFA_FULL || doc_type == FORMTYPE_XFA_FOREGROUND)
414     FPDF_LoadXFA(document_ptr);
415 
416   (void)FPDF_GetDocPermissions(document_ptr);
417   return true;
418 }
419 
CloseDocument()420 void EmbedderTest::CloseDocument() {
421   FORM_DoDocumentAAction(form_handle(), FPDFDOC_AACTION_WC);
422   form_handle_.reset();
423   document_.reset();
424   avail_.reset();
425   fake_file_access_.reset();
426   memset(&file_access_, 0, sizeof(file_access_));
427   loader_.reset();
428   file_contents_.reset();
429 }
430 
SetupFormFillEnvironment(FPDF_DOCUMENT doc,JavaScriptOption javascript_option)431 FPDF_FORMHANDLE EmbedderTest::SetupFormFillEnvironment(
432     FPDF_DOCUMENT doc,
433     JavaScriptOption javascript_option) {
434   IPDF_JSPLATFORM* platform = static_cast<IPDF_JSPLATFORM*>(this);
435   memset(platform, '\0', sizeof(IPDF_JSPLATFORM));
436   platform->version = 3;
437   platform->app_alert = AlertTrampoline;
438 
439   FPDF_FORMFILLINFO* formfillinfo = static_cast<FPDF_FORMFILLINFO*>(this);
440   memset(formfillinfo, 0, sizeof(FPDF_FORMFILLINFO));
441   formfillinfo->version = form_fill_info_version_;
442   formfillinfo->FFI_Invalidate = InvalidateStub;
443   formfillinfo->FFI_OutputSelectedRect = OutputSelectedRectStub;
444   formfillinfo->FFI_SetCursor = SetCursorStub;
445   formfillinfo->FFI_SetTimer = SetTimerTrampoline;
446   formfillinfo->FFI_KillTimer = KillTimerTrampoline;
447   formfillinfo->FFI_GetLocalTime = GetLocalTimeStub;
448   formfillinfo->FFI_OnChange = OnChangeStub;
449   formfillinfo->FFI_GetPage = GetPageTrampoline;
450   formfillinfo->FFI_GetCurrentPage = GetCurrentPageStub;
451   formfillinfo->FFI_GetRotation = GetRotationStub;
452   formfillinfo->FFI_ExecuteNamedAction = ExecuteNamedActionStub;
453   formfillinfo->FFI_SetTextFieldFocus = SetTextFieldFocusStub;
454   formfillinfo->FFI_DoURIAction = DoURIActionTrampoline;
455   formfillinfo->FFI_DoGoToAction = DoGoToActionTrampoline;
456 #ifdef PDF_ENABLE_XFA
457   formfillinfo->FFI_DisplayCaret = DisplayCaretStub;
458   formfillinfo->FFI_GetCurrentPageIndex = GetCurrentPageIndexStub;
459   formfillinfo->FFI_SetCurrentPage = SetCurrentPageStub;
460   formfillinfo->FFI_GotoURL = GotoURLStub;
461   formfillinfo->FFI_GetPageViewRect = GetPageViewRectStub;
462   formfillinfo->FFI_PageEvent = PageEventStub;
463   formfillinfo->FFI_PopupMenu = PopupMenuStub;
464   formfillinfo->FFI_OpenFile = OpenFileStub;
465   formfillinfo->FFI_EmailTo = EmailToStub;
466   formfillinfo->FFI_UploadTo = UploadToStub;
467   formfillinfo->FFI_GetPlatform = GetPlatformStub;
468   formfillinfo->FFI_GetLanguage = GetLanguageStub;
469   formfillinfo->FFI_DownloadFromURL = DownloadFromURLStub;
470   formfillinfo->FFI_PostRequestURL = PostRequestURLStub;
471   formfillinfo->FFI_PutRequestURL = PutRequestURLStub;
472 #endif  // PDF_ENABLE_XFA
473   formfillinfo->FFI_OnFocusChange = OnFocusChangeTrampoline;
474   formfillinfo->FFI_DoURIActionWithKeyboardModifier =
475       DoURIActionWithKeyboardModifierTrampoline;
476 
477   if (javascript_option == JavaScriptOption::kEnableJavaScript)
478     formfillinfo->m_pJsPlatform = platform;
479 
480   FPDF_FORMHANDLE form_handle =
481       FPDFDOC_InitFormFillEnvironment(doc, formfillinfo);
482   SetInitialFormFieldHighlight(form_handle);
483   return form_handle;
484 }
485 
DoOpenActions()486 void EmbedderTest::DoOpenActions() {
487   DCHECK(form_handle());
488   FORM_DoDocumentJSAction(form_handle());
489   FORM_DoDocumentOpenAction(form_handle());
490 }
491 
GetFirstPageNum()492 int EmbedderTest::GetFirstPageNum() {
493   int first_page = FPDFAvail_GetFirstPageNum(document());
494   (void)FPDFAvail_IsPageAvail(avail(), first_page,
495                               fake_file_access_->GetDownloadHints());
496   return first_page;
497 }
498 
GetPageCount()499 int EmbedderTest::GetPageCount() {
500   int page_count = FPDF_GetPageCount(document());
501   for (int i = 0; i < page_count; ++i)
502     (void)FPDFAvail_IsPageAvail(avail(), i,
503                                 fake_file_access_->GetDownloadHints());
504   return page_count;
505 }
506 
LoadPage(int page_number)507 FPDF_PAGE EmbedderTest::LoadPage(int page_number) {
508   return LoadPageCommon(page_number, true);
509 }
510 
LoadPageNoEvents(int page_number)511 FPDF_PAGE EmbedderTest::LoadPageNoEvents(int page_number) {
512   return LoadPageCommon(page_number, false);
513 }
514 
LoadPageCommon(int page_number,bool do_events)515 FPDF_PAGE EmbedderTest::LoadPageCommon(int page_number, bool do_events) {
516   DCHECK(form_handle());
517   DCHECK(page_number >= 0);
518   DCHECK(!pdfium::Contains(page_map_, page_number));
519 
520   FPDF_PAGE page = FPDF_LoadPage(document(), page_number);
521   if (!page)
522     return nullptr;
523 
524   if (do_events) {
525     FORM_OnAfterLoadPage(page, form_handle());
526     FORM_DoPageAAction(page, form_handle(), FPDFPAGE_AACTION_OPEN);
527   }
528   page_map_[page_number] = page;
529   return page;
530 }
531 
UnloadPage(FPDF_PAGE page)532 void EmbedderTest::UnloadPage(FPDF_PAGE page) {
533   UnloadPageCommon(page, true);
534 }
535 
UnloadPageNoEvents(FPDF_PAGE page)536 void EmbedderTest::UnloadPageNoEvents(FPDF_PAGE page) {
537   UnloadPageCommon(page, false);
538 }
539 
UnloadPageCommon(FPDF_PAGE page,bool do_events)540 void EmbedderTest::UnloadPageCommon(FPDF_PAGE page, bool do_events) {
541   DCHECK(form_handle());
542   int page_number = GetPageNumberForLoadedPage(page);
543   if (page_number < 0) {
544     NOTREACHED();
545     return;
546   }
547   if (do_events) {
548     FORM_DoPageAAction(page, form_handle(), FPDFPAGE_AACTION_CLOSE);
549     FORM_OnBeforeClosePage(page, form_handle());
550   }
551   FPDF_ClosePage(page);
552   page_map_.erase(page_number);
553 }
554 
SetInitialFormFieldHighlight(FPDF_FORMHANDLE form)555 void EmbedderTest::SetInitialFormFieldHighlight(FPDF_FORMHANDLE form) {
556   FPDF_SetFormFieldHighlightColor(form, FPDF_FORMFIELD_UNKNOWN, 0xFFE4DD);
557   FPDF_SetFormFieldHighlightAlpha(form, 100);
558 }
559 
RenderLoadedPage(FPDF_PAGE page)560 ScopedFPDFBitmap EmbedderTest::RenderLoadedPage(FPDF_PAGE page) {
561   return RenderLoadedPageWithFlags(page, 0);
562 }
563 
RenderLoadedPageWithFlags(FPDF_PAGE page,int flags)564 ScopedFPDFBitmap EmbedderTest::RenderLoadedPageWithFlags(FPDF_PAGE page,
565                                                          int flags) {
566   if (GetPageNumberForLoadedPage(page) < 0) {
567     NOTREACHED();
568     return nullptr;
569   }
570   return RenderPageWithFlags(page, form_handle(), flags);
571 }
572 
RenderSavedPage(FPDF_PAGE page)573 ScopedFPDFBitmap EmbedderTest::RenderSavedPage(FPDF_PAGE page) {
574   return RenderSavedPageWithFlags(page, 0);
575 }
576 
RenderSavedPageWithFlags(FPDF_PAGE page,int flags)577 ScopedFPDFBitmap EmbedderTest::RenderSavedPageWithFlags(FPDF_PAGE page,
578                                                         int flags) {
579   if (GetPageNumberForSavedPage(page) < 0) {
580     NOTREACHED();
581     return nullptr;
582   }
583   return RenderPageWithFlags(page, saved_form_handle(), flags);
584 }
585 
586 // static
RenderPageWithFlags(FPDF_PAGE page,FPDF_FORMHANDLE handle,int flags)587 ScopedFPDFBitmap EmbedderTest::RenderPageWithFlags(FPDF_PAGE page,
588                                                    FPDF_FORMHANDLE handle,
589                                                    int flags) {
590   int width = static_cast<int>(FPDF_GetPageWidthF(page));
591   int height = static_cast<int>(FPDF_GetPageHeightF(page));
592   int alpha = FPDFPage_HasTransparency(page) ? 1 : 0;
593   ScopedFPDFBitmap bitmap(FPDFBitmap_Create(width, height, alpha));
594   FPDF_DWORD fill_color = alpha ? 0x00000000 : 0xFFFFFFFF;
595   FPDFBitmap_FillRect(bitmap.get(), 0, 0, width, height, fill_color);
596   FPDF_RenderPageBitmap(bitmap.get(), page, 0, 0, width, height, 0, flags);
597   FPDF_FFLDraw(handle, bitmap.get(), page, 0, 0, width, height, 0, flags);
598   return bitmap;
599 }
600 
601 // static
RenderPage(FPDF_PAGE page)602 ScopedFPDFBitmap EmbedderTest::RenderPage(FPDF_PAGE page) {
603   return RenderPageWithFlags(page, nullptr, 0);
604 }
605 
606 #if BUILDFLAG(IS_WIN)
607 // static
RenderPageWithFlagsToEmf(FPDF_PAGE page,int flags)608 std::vector<uint8_t> EmbedderTest::RenderPageWithFlagsToEmf(FPDF_PAGE page,
609                                                             int flags) {
610   HDC dc = CreateEnhMetaFileA(nullptr, nullptr, nullptr, nullptr);
611 
612   int width = static_cast<int>(FPDF_GetPageWidthF(page));
613   int height = static_cast<int>(FPDF_GetPageHeightF(page));
614   HRGN rgn = CreateRectRgn(0, 0, width, height);
615   SelectClipRgn(dc, rgn);
616   DeleteObject(rgn);
617 
618   SelectObject(dc, GetStockObject(NULL_PEN));
619   SelectObject(dc, GetStockObject(WHITE_BRUSH));
620   // If a PS_NULL pen is used, the dimensions of the rectangle are 1 pixel less.
621   Rectangle(dc, 0, 0, width + 1, height + 1);
622 
623   FPDF_RenderPage(dc, page, 0, 0, width, height, 0, flags);
624 
625   HENHMETAFILE emf = CloseEnhMetaFile(dc);
626   UINT size_in_bytes = GetEnhMetaFileBits(emf, 0, nullptr);
627   std::vector<uint8_t> buffer(size_in_bytes);
628   GetEnhMetaFileBits(emf, size_in_bytes, buffer.data());
629   DeleteEnhMetaFile(emf);
630   return buffer;
631 }
632 
633 // static
GetPostScriptFromEmf(pdfium::span<const uint8_t> emf_data)634 std::string EmbedderTest::GetPostScriptFromEmf(
635     pdfium::span<const uint8_t> emf_data) {
636   // This comes from Emf::InitFromData() in Chromium.
637   HENHMETAFILE emf = SetEnhMetaFileBits(
638       pdfium::base::checked_cast<UINT>(emf_data.size()), emf_data.data());
639   if (!emf)
640     return std::string();
641 
642   // This comes from Emf::Enumerator::Enumerator() in Chromium.
643   std::vector<const ENHMETARECORD*> records;
644   if (!EnumEnhMetaFile(nullptr, emf, &GetRecordProc, &records, nullptr)) {
645     DeleteEnhMetaFile(emf);
646     return std::string();
647   }
648 
649   // This comes from PostScriptMetaFile::SafePlayback() in Chromium.
650   std::string ps_data;
651   for (const auto* record : records) {
652     if (record->iType != EMR_GDICOMMENT)
653       continue;
654 
655     // PostScript data is encapsulated inside EMF comment records.
656     // The first two bytes of the comment indicate the string length. The rest
657     // is the actual string data.
658     const auto* comment = reinterpret_cast<const EMRGDICOMMENT*>(record);
659     const char* data = reinterpret_cast<const char*>(comment->Data);
660     uint16_t size = *reinterpret_cast<const uint16_t*>(data);
661     data += 2;
662     ps_data.append(data, size);
663   }
664   DeleteEnhMetaFile(emf);
665   return ps_data;
666 }
667 #endif  // BUILDFLAG(IS_WIN)
668 
OpenSavedDocument()669 FPDF_DOCUMENT EmbedderTest::OpenSavedDocument() {
670   return OpenSavedDocumentWithPassword(nullptr);
671 }
672 
673 // static
BytesPerPixelForFormat(int format)674 int EmbedderTest::BytesPerPixelForFormat(int format) {
675   switch (format) {
676     case FPDFBitmap_Gray:
677       return 1;
678     case FPDFBitmap_BGR:
679       return 3;
680     case FPDFBitmap_BGRx:
681     case FPDFBitmap_BGRA:
682       return 4;
683     default:
684       NOTREACHED();
685       return 0;
686   }
687 }
688 
OpenSavedDocumentWithPassword(const char * password)689 FPDF_DOCUMENT EmbedderTest::OpenSavedDocumentWithPassword(
690     const char* password) {
691   memset(&saved_file_access_, 0, sizeof(saved_file_access_));
692   saved_file_access_.m_FileLen =
693       pdfium::base::checked_cast<unsigned long>(data_string_.size());
694   saved_file_access_.m_GetBlock = GetBlockFromString;
695   // Copy data to prevent clearing it before saved document close.
696   saved_document_file_data_ = data_string_;
697   saved_file_access_.m_Param = &saved_document_file_data_;
698 
699   saved_fake_file_access_ =
700       std::make_unique<FakeFileAccess>(&saved_file_access_);
701 
702   EXPECT_TRUE(OpenDocumentHelper(
703       password, LinearizeOption::kDefaultLinearize,
704       JavaScriptOption::kEnableJavaScript, saved_fake_file_access_.get(),
705       &saved_document_, &saved_avail_, &saved_form_handle_));
706   return saved_document();
707 }
708 
CloseSavedDocument()709 void EmbedderTest::CloseSavedDocument() {
710   DCHECK(saved_document());
711 
712   saved_form_handle_.reset();
713   saved_document_.reset();
714   saved_avail_.reset();
715 }
716 
LoadSavedPage(int page_number)717 FPDF_PAGE EmbedderTest::LoadSavedPage(int page_number) {
718   DCHECK(saved_form_handle());
719   DCHECK(page_number >= 0);
720   DCHECK(!pdfium::Contains(saved_page_map_, page_number));
721 
722   FPDF_PAGE page = FPDF_LoadPage(saved_document(), page_number);
723   if (!page)
724     return nullptr;
725 
726   FORM_OnAfterLoadPage(page, saved_form_handle());
727   FORM_DoPageAAction(page, saved_form_handle(), FPDFPAGE_AACTION_OPEN);
728   saved_page_map_[page_number] = page;
729   return page;
730 }
731 
CloseSavedPage(FPDF_PAGE page)732 void EmbedderTest::CloseSavedPage(FPDF_PAGE page) {
733   DCHECK(saved_form_handle());
734 
735   int page_number = GetPageNumberForSavedPage(page);
736   if (page_number < 0) {
737     NOTREACHED();
738     return;
739   }
740 
741   FORM_DoPageAAction(page, saved_form_handle(), FPDFPAGE_AACTION_CLOSE);
742   FORM_OnBeforeClosePage(page, saved_form_handle());
743   FPDF_ClosePage(page);
744 
745   saved_page_map_.erase(page_number);
746 }
747 
VerifySavedRendering(FPDF_PAGE page,int width,int height,const char * md5)748 void EmbedderTest::VerifySavedRendering(FPDF_PAGE page,
749                                         int width,
750                                         int height,
751                                         const char* md5) {
752   DCHECK(saved_document());
753   DCHECK(page);
754 
755   ScopedFPDFBitmap bitmap = RenderSavedPageWithFlags(page, FPDF_ANNOT);
756   CompareBitmap(bitmap.get(), width, height, md5);
757 }
758 
VerifySavedDocument(int width,int height,const char * md5)759 void EmbedderTest::VerifySavedDocument(int width, int height, const char* md5) {
760   ASSERT_TRUE(OpenSavedDocument());
761   FPDF_PAGE page = LoadSavedPage(0);
762   VerifySavedRendering(page, width, height, md5);
763   CloseSavedPage(page);
764   CloseSavedDocument();
765 }
766 
SetWholeFileAvailable()767 void EmbedderTest::SetWholeFileAvailable() {
768   DCHECK(fake_file_access_);
769   fake_file_access_->SetWholeFileAvailable();
770 }
771 
SetDocumentFromAvail()772 void EmbedderTest::SetDocumentFromAvail() {
773   document_.reset(FPDFAvail_GetDocument(avail(), nullptr));
774 }
775 
CreateAvail(FX_FILEAVAIL * file_avail,FPDF_FILEACCESS * file)776 void EmbedderTest::CreateAvail(FX_FILEAVAIL* file_avail,
777                                FPDF_FILEACCESS* file) {
778   avail_.reset(FPDFAvail_Create(file_avail, file));
779 }
780 
GetPage(FPDF_FORMFILLINFO * info,FPDF_DOCUMENT document,int page_index)781 FPDF_PAGE EmbedderTest::Delegate::GetPage(FPDF_FORMFILLINFO* info,
782                                           FPDF_DOCUMENT document,
783                                           int page_index) {
784   EmbedderTest* test = static_cast<EmbedderTest*>(info);
785   auto it = test->page_map_.find(page_index);
786   return it != test->page_map_.end() ? it->second : nullptr;
787 }
788 
789 // static
HashBitmap(FPDF_BITMAP bitmap)790 std::string EmbedderTest::HashBitmap(FPDF_BITMAP bitmap) {
791   int stride = FPDFBitmap_GetStride(bitmap);
792   int usable_bytes_per_row =
793       GetBitmapBytesPerPixel(bitmap) * FPDFBitmap_GetWidth(bitmap);
794   int height = FPDFBitmap_GetHeight(bitmap);
795   auto span = pdfium::make_span(
796       static_cast<uint8_t*>(FPDFBitmap_GetBuffer(bitmap)), stride * height);
797 
798   CRYPT_md5_context context = CRYPT_MD5Start();
799   for (int i = 0; i < height; ++i)
800     CRYPT_MD5Update(&context, span.subspan(i * stride, usable_bytes_per_row));
801   uint8_t digest[16];
802   CRYPT_MD5Finish(&context, digest);
803   return CryptToBase16(digest);
804 }
805 
806 // static
WriteBitmapToPng(FPDF_BITMAP bitmap,const std::string & filename)807 void EmbedderTest::WriteBitmapToPng(FPDF_BITMAP bitmap,
808                                     const std::string& filename) {
809   BitmapSaver::WriteBitmapToPng(bitmap, filename);
810 }
811 
812 // static
CompareBitmap(FPDF_BITMAP bitmap,int expected_width,int expected_height,const char * expected_md5sum)813 void EmbedderTest::CompareBitmap(FPDF_BITMAP bitmap,
814                                  int expected_width,
815                                  int expected_height,
816                                  const char* expected_md5sum) {
817   ASSERT_EQ(expected_width, FPDFBitmap_GetWidth(bitmap));
818   ASSERT_EQ(expected_height, FPDFBitmap_GetHeight(bitmap));
819 
820   // The expected stride is calculated using the same formula as in
821   // CFX_DIBitmap::CalculatePitchAndSize(), which sets the bitmap stride.
822   const int expected_stride =
823       (expected_width * GetBitmapBytesPerPixel(bitmap) * 8 + 31) / 32 * 4;
824   ASSERT_EQ(expected_stride, FPDFBitmap_GetStride(bitmap));
825 
826   if (!expected_md5sum)
827     return;
828 
829   std::string actual_md5sum = HashBitmap(bitmap);
830   EXPECT_EQ(expected_md5sum, actual_md5sum);
831   if (EmbedderTestEnvironment::GetInstance()->write_pngs()) {
832     WriteBitmapToPng(bitmap, actual_md5sum + ".png");
833   }
834 }
835 
836 // static
WriteBlockCallback(FPDF_FILEWRITE * pFileWrite,const void * data,unsigned long size)837 int EmbedderTest::WriteBlockCallback(FPDF_FILEWRITE* pFileWrite,
838                                      const void* data,
839                                      unsigned long size) {
840   EmbedderTest* pThis = static_cast<EmbedderTest*>(pFileWrite);
841 
842   pThis->data_string_.append(static_cast<const char*>(data), size);
843 
844   if (pThis->filestream_.is_open())
845     pThis->filestream_.write(static_cast<const char*>(data), size);
846 
847   return 1;
848 }
849 
850 // static
GetBlockFromString(void * param,unsigned long pos,unsigned char * buf,unsigned long size)851 int EmbedderTest::GetBlockFromString(void* param,
852                                      unsigned long pos,
853                                      unsigned char* buf,
854                                      unsigned long size) {
855   std::string* new_file = static_cast<std::string*>(param);
856   if (!new_file || pos + size < pos) {
857     NOTREACHED();
858     return 0;
859   }
860 
861   if (pos + size > new_file->size()) {
862     NOTREACHED();
863     return 0;
864   }
865 
866   memcpy(buf, new_file->data() + pos, size);
867   return 1;
868 }
869 
870 // static
GetPageNumberForPage(const PageNumberToHandleMap & page_map,FPDF_PAGE page)871 int EmbedderTest::GetPageNumberForPage(const PageNumberToHandleMap& page_map,
872                                        FPDF_PAGE page) {
873   for (const auto& it : page_map) {
874     if (it.second == page) {
875       int page_number = it.first;
876       DCHECK(page_number >= 0);
877       return page_number;
878     }
879   }
880   return -1;
881 }
882 
GetPageNumberForLoadedPage(FPDF_PAGE page) const883 int EmbedderTest::GetPageNumberForLoadedPage(FPDF_PAGE page) const {
884   return GetPageNumberForPage(page_map_, page);
885 }
886 
GetPageNumberForSavedPage(FPDF_PAGE page) const887 int EmbedderTest::GetPageNumberForSavedPage(FPDF_PAGE page) const {
888   return GetPageNumberForPage(saved_page_map_, page);
889 }
890 
891 #ifndef NDEBUG
OpenPDFFileForWrite(const std::string & filename)892 void EmbedderTest::OpenPDFFileForWrite(const std::string& filename) {
893   filestream_.open(filename, std::ios_base::binary);
894 }
895 
ClosePDFFileForWrite()896 void EmbedderTest::ClosePDFFileForWrite() {
897   filestream_.close();
898 }
899 #endif
900