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