Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
embedder_test.cpp
Go to the documentation of this file.
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
33namespace {
34
35int GetBitmapBytesPerPixel(FPDF_BITMAP bitmap) {
37}
38
39#if BUILDFLAG(IS_WIN)
40int 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.
52void UnsupportedHandlerTrampoline(UNSUPPORT_INFO* info, int type) {
53 auto* delegate = static_cast<EmbedderTest*>(info)->GetDelegate();
54 delegate->UnsupportedHandler(type);
55}
56
57int 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
66int SetTimerTrampoline(FPDF_FORMFILLINFO* info, int msecs, TimerCallback fn) {
67 auto* delegate = static_cast<EmbedderTest*>(info)->GetDelegate();
68 return delegate->SetTimer(msecs, fn);
69}
70
71void KillTimerTrampoline(FPDF_FORMFILLINFO* info, int id) {
72 auto* delegate = static_cast<EmbedderTest*>(info)->GetDelegate();
73 return delegate->KillTimer(id);
74}
75
76FPDF_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
83void DoURIActionTrampoline(FPDF_FORMFILLINFO* info, FPDF_BYTESTRING uri) {
84 auto* delegate = static_cast<EmbedderTest*>(info)->GetDelegate();
85 return delegate->DoURIAction(uri);
86}
87
88void 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
98void 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
105void 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).
113void InvalidateStub(FPDF_FORMFILLINFO* pThis,
114 FPDF_PAGE page,
115 double left,
116 double top,
117 double right,
118 double bottom) {}
119
120void OutputSelectedRectStub(FPDF_FORMFILLINFO* pThis,
121 FPDF_PAGE page,
122 double left,
123 double top,
124 double right,
125 double bottom) {}
126
127void SetCursorStub(FPDF_FORMFILLINFO* pThis, int nCursorType) {}
128
129FPDF_SYSTEMTIME GetLocalTimeStub(FPDF_FORMFILLINFO* pThis) {
130 return {122, 11, 6, 28, 12, 59, 59, 500};
131}
132
133void OnChangeStub(FPDF_FORMFILLINFO* pThis) {}
134
135FPDF_PAGE GetCurrentPageStub(FPDF_FORMFILLINFO* pThis, FPDF_DOCUMENT document) {
136 return GetPageTrampoline(pThis, document, 0);
137}
138
139int GetRotationStub(FPDF_FORMFILLINFO* pThis, FPDF_PAGE page) {
140 return 0;
141}
142
143void ExecuteNamedActionStub(FPDF_FORMFILLINFO* pThis, FPDF_BYTESTRING name) {}
144
145void SetTextFieldFocusStub(FPDF_FORMFILLINFO* pThis,
146 FPDF_WIDESTRING value,
147 FPDF_DWORD valueLen,
148 FPDF_BOOL is_focus) {}
149
150#ifdef PDF_ENABLE_XFA
151void 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
159int GetCurrentPageIndexStub(FPDF_FORMFILLINFO* pThis, FPDF_DOCUMENT document) {
160 return 0;
161}
162
163void SetCurrentPageStub(FPDF_FORMFILLINFO* pThis,
164 FPDF_DOCUMENT document,
165 int iCurPage) {}
166
167void GotoURLStub(FPDF_FORMFILLINFO* pThis,
168 FPDF_DOCUMENT document,
169 FPDF_WIDESTRING wsURL) {}
170
171void 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
183void PageEventStub(FPDF_FORMFILLINFO* pThis,
184 int page_count,
185 FPDF_DWORD event_type) {}
186
187FPDF_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
196FPDF_FILEHANDLER* OpenFileStub(FPDF_FORMFILLINFO* pThis,
197 int fileFlag,
198 FPDF_WIDESTRING wsURL,
199 const char* mode) {
200 return nullptr;
201}
202
203void 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
211void UploadToStub(FPDF_FORMFILLINFO* pThis,
212 FPDF_FILEHANDLER* fileHandler,
213 int fileFlag,
214 FPDF_WIDESTRING uploadTo) {}
215
216int GetPlatformStub(FPDF_FORMFILLINFO* pThis, void* platform, int length) {
217 return 0;
218}
219
220int GetLanguageStub(FPDF_FORMFILLINFO* pThis, void* language, int length) {
221 return 0;
222}
223
224FPDF_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
243FPDF_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
255FPDF_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
268 FPDF_FILEWRITE::version = 1;
269 FPDF_FILEWRITE::WriteBlock = WriteBlockCallback;
270}
271
272EmbedderTest::~EmbedderTest() = default;
273
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;
280}
281
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())
289}
290
293 form_handle_.reset(SetupFormFillEnvironment(
294 document(), JavaScriptOption::kEnableJavaScript));
295}
296
298 document_.reset(FPDF_CreateNewDocument());
299 DCHECK(document_);
300}
301
302bool EmbedderTest::OpenDocument(const std::string& filename) {
303 return OpenDocumentWithOptions(filename, nullptr,
306}
307
308bool EmbedderTest::OpenDocumentLinearized(const std::string& filename) {
309 return OpenDocumentWithOptions(filename, nullptr,
312}
313
314bool EmbedderTest::OpenDocumentWithPassword(const std::string& filename,
315 const char* password) {
316 return OpenDocumentWithOptions(filename, password,
319}
320
321bool EmbedderTest::OpenDocumentWithoutJavaScript(const std::string& filename) {
322 return OpenDocumentWithOptions(filename, nullptr,
325}
326
327bool EmbedderTest::OpenDocumentWithOptions(const std::string& filename,
328 const char* password,
329 LinearizeOption linearize_option,
330 JavaScriptOption javascript_option) {
331 std::string file_path = PathService::GetTestFilePath(filename);
332 if (file_path.empty()) {
333 return false;
334 }
335
336 file_contents_ = GetFileContents(file_path.c_str());
337 if (file_contents_.empty()) {
338 return false;
339 }
340
341 EXPECT_TRUE(!loader_);
342 loader_ = std::make_unique<TestLoader>(file_contents_);
343
344 memset(&file_access_, 0, sizeof(file_access_));
345 file_access_.m_FileLen =
346 pdfium::base::checked_cast<unsigned long>(file_contents_.size());
347 file_access_.m_GetBlock = TestLoader::GetBlock;
348 file_access_.m_Param = loader_.get();
349
350 fake_file_access_ = std::make_unique<FakeFileAccess>(&file_access_);
351 return OpenDocumentHelper(password, linearize_option, javascript_option,
352 fake_file_access_.get(), &document_, &avail_,
353 &form_handle_);
354}
355
356bool EmbedderTest::OpenDocumentHelper(const char* password,
357 LinearizeOption linearize_option,
358 JavaScriptOption javascript_option,
359 FakeFileAccess* network_simulator,
360 ScopedFPDFDocument* document,
361 ScopedFPDFAvail* avail,
362 ScopedFPDFFormHandle* form_handle) {
363 network_simulator->AddSegment(0, 1024);
364 network_simulator->SetRequestedDataAvailable();
365 avail->reset(FPDFAvail_Create(network_simulator->GetFileAvail(),
366 network_simulator->GetFileAccess()));
367 FPDF_AVAIL avail_ptr = avail->get();
368 FPDF_DOCUMENT document_ptr = nullptr;
370 int32_t nRet = PDF_DATA_NOTAVAIL;
371 while (nRet == PDF_DATA_NOTAVAIL) {
372 network_simulator->SetRequestedDataAvailable();
373 nRet = FPDFAvail_IsDocAvail(avail_ptr,
374 network_simulator->GetDownloadHints());
375 }
376 if (nRet == PDF_DATA_ERROR)
377 return false;
378
379 document->reset(FPDFAvail_GetDocument(avail_ptr, password));
380 document_ptr = document->get();
381 if (!document_ptr)
382 return false;
383
384 nRet = PDF_DATA_NOTAVAIL;
385 while (nRet == PDF_DATA_NOTAVAIL) {
386 network_simulator->SetRequestedDataAvailable();
387 nRet = FPDFAvail_IsFormAvail(avail_ptr,
388 network_simulator->GetDownloadHints());
389 }
390 if (nRet == PDF_FORM_ERROR)
391 return false;
392
393 int page_count = FPDF_GetPageCount(document_ptr);
394 for (int i = 0; i < page_count; ++i) {
395 nRet = PDF_DATA_NOTAVAIL;
396 while (nRet == PDF_DATA_NOTAVAIL) {
397 network_simulator->SetRequestedDataAvailable();
398 nRet = FPDFAvail_IsPageAvail(avail_ptr, i,
399 network_simulator->GetDownloadHints());
400 }
401 if (nRet == PDF_DATA_ERROR)
402 return false;
403 }
404 } else {
405 if (linearize_option == LinearizeOption::kMustLinearize)
406 return false;
407 network_simulator->SetWholeFileAvailable();
408 document->reset(
409 FPDF_LoadCustomDocument(network_simulator->GetFileAccess(), password));
410 document_ptr = document->get();
411 if (!document_ptr)
412 return false;
413 }
414 form_handle->reset(SetupFormFillEnvironment(document_ptr, javascript_option));
415
416 int doc_type = FPDF_GetFormType(document_ptr);
417 if (doc_type == FORMTYPE_XFA_FULL || doc_type == FORMTYPE_XFA_FOREGROUND)
418 FPDF_LoadXFA(document_ptr);
419
420 return true;
421}
422
425 form_handle_.reset();
426 document_.reset();
427 avail_.reset();
428 fake_file_access_.reset();
429 memset(&file_access_, 0, sizeof(file_access_));
430 loader_.reset();
431 file_contents_ = {};
432}
433
435 FPDF_DOCUMENT doc,
436 JavaScriptOption javascript_option) {
437 IPDF_JSPLATFORM* platform = static_cast<IPDF_JSPLATFORM*>(this);
438 memset(platform, '\0', sizeof(IPDF_JSPLATFORM));
439 platform->version = 3;
440 platform->app_alert = AlertTrampoline;
441
442 FPDF_FORMFILLINFO* formfillinfo = static_cast<FPDF_FORMFILLINFO*>(this);
443 memset(formfillinfo, 0, sizeof(FPDF_FORMFILLINFO));
444 formfillinfo->version = form_fill_info_version_;
445 formfillinfo->FFI_Invalidate = InvalidateStub;
446 formfillinfo->FFI_OutputSelectedRect = OutputSelectedRectStub;
447 formfillinfo->FFI_SetCursor = SetCursorStub;
448 formfillinfo->FFI_SetTimer = SetTimerTrampoline;
449 formfillinfo->FFI_KillTimer = KillTimerTrampoline;
450 formfillinfo->FFI_GetLocalTime = GetLocalTimeStub;
451 formfillinfo->FFI_OnChange = OnChangeStub;
452 formfillinfo->FFI_GetPage = GetPageTrampoline;
453 formfillinfo->FFI_GetCurrentPage = GetCurrentPageStub;
454 formfillinfo->FFI_GetRotation = GetRotationStub;
455 formfillinfo->FFI_ExecuteNamedAction = ExecuteNamedActionStub;
456 formfillinfo->FFI_SetTextFieldFocus = SetTextFieldFocusStub;
457 formfillinfo->FFI_DoURIAction = DoURIActionTrampoline;
458 formfillinfo->FFI_DoGoToAction = DoGoToActionTrampoline;
459#ifdef PDF_ENABLE_XFA
460 formfillinfo->FFI_DisplayCaret = DisplayCaretStub;
461 formfillinfo->FFI_GetCurrentPageIndex = GetCurrentPageIndexStub;
462 formfillinfo->FFI_SetCurrentPage = SetCurrentPageStub;
463 formfillinfo->FFI_GotoURL = GotoURLStub;
464 formfillinfo->FFI_GetPageViewRect = GetPageViewRectStub;
465 formfillinfo->FFI_PageEvent = PageEventStub;
466 formfillinfo->FFI_PopupMenu = PopupMenuStub;
467 formfillinfo->FFI_OpenFile = OpenFileStub;
468 formfillinfo->FFI_EmailTo = EmailToStub;
469 formfillinfo->FFI_UploadTo = UploadToStub;
470 formfillinfo->FFI_GetPlatform = GetPlatformStub;
471 formfillinfo->FFI_GetLanguage = GetLanguageStub;
472 formfillinfo->FFI_DownloadFromURL = DownloadFromURLStub;
473 formfillinfo->FFI_PostRequestURL = PostRequestURLStub;
474 formfillinfo->FFI_PutRequestURL = PutRequestURLStub;
475#endif // PDF_ENABLE_XFA
476 formfillinfo->FFI_OnFocusChange = OnFocusChangeTrampoline;
478 DoURIActionWithKeyboardModifierTrampoline;
479
480 if (javascript_option == JavaScriptOption::kEnableJavaScript)
481 formfillinfo->m_pJsPlatform = platform;
482
483 FPDF_FORMHANDLE form_handle =
486 return form_handle;
487}
488
494
497 (void)FPDFAvail_IsPageAvail(avail(), first_page,
498 fake_file_access_->GetDownloadHints());
499 return first_page;
500}
501
503 int page_count = FPDF_GetPageCount(document());
504 for (int i = 0; i < page_count; ++i)
505 (void)FPDFAvail_IsPageAvail(avail(), i,
506 fake_file_access_->GetDownloadHints());
507 return page_count;
508}
509
510FPDF_PAGE EmbedderTest::LoadPage(int page_number) {
511 return LoadPageCommon(page_number, true);
512}
513
514FPDF_PAGE EmbedderTest::LoadPageNoEvents(int page_number) {
515 return LoadPageCommon(page_number, false);
516}
517
518FPDF_PAGE EmbedderTest::LoadPageCommon(int page_number, bool do_events) {
519 DCHECK(form_handle());
520 DCHECK(page_number >= 0);
521 DCHECK(!pdfium::Contains(page_map_, page_number));
522
523 FPDF_PAGE page = FPDF_LoadPage(document(), page_number);
524 if (!page)
525 return nullptr;
526
527 if (do_events) {
530 }
531 page_map_[page_number] = page;
532 return page;
533}
534
535void EmbedderTest::UnloadPage(FPDF_PAGE page) {
536 UnloadPageCommon(page, true);
537}
538
539void EmbedderTest::UnloadPageNoEvents(FPDF_PAGE page) {
540 UnloadPageCommon(page, false);
541}
542
543void EmbedderTest::UnloadPageCommon(FPDF_PAGE page, bool do_events) {
544 DCHECK(form_handle());
545 int page_number = GetPageNumberForLoadedPage(page);
546 CHECK_GE(page_number, 0);
547
548 if (do_events) {
551 }
553 page_map_.erase(page_number);
554}
555
560
562 return RenderLoadedPageWithFlags(page, 0);
563}
564
566 int flags) {
567 int page_number = GetPageNumberForLoadedPage(page);
568 CHECK_GE(page_number, 0);
569 return RenderPageWithFlags(page, form_handle(), flags);
570}
571
573 return RenderSavedPageWithFlags(page, 0);
574}
575
577 int flags) {
578 int page_number = GetPageNumberForSavedPage(page);
579 CHECK_GE(page_number, 0);
580 return RenderPageWithFlags(page, saved_form_handle(), flags);
581}
582
583// static
584ScopedFPDFBitmap EmbedderTest::RenderPageWithFlags(FPDF_PAGE page,
585 FPDF_FORMHANDLE handle,
586 int flags) {
587 int width = static_cast<int>(FPDF_GetPageWidthF(page));
588 int height = static_cast<int>(FPDF_GetPageHeightF(page));
589 int alpha = FPDFPage_HasTransparency(page) ? 1 : 0;
590 ScopedFPDFBitmap bitmap(FPDFBitmap_Create(width, height, alpha));
591 FPDF_DWORD fill_color = alpha ? 0x00000000 : 0xFFFFFFFF;
592 FPDFBitmap_FillRect(bitmap.get(), 0, 0, width, height, fill_color);
593 FPDF_RenderPageBitmap(bitmap.get(), page, 0, 0, width, height, 0, flags);
594 FPDF_FFLDraw(handle, bitmap.get(), page, 0, 0, width, height, 0, flags);
595 return bitmap;
596}
597
598// static
599ScopedFPDFBitmap EmbedderTest::RenderPage(FPDF_PAGE page) {
600 return RenderPageWithFlags(page, nullptr, 0);
601}
602
603#if BUILDFLAG(IS_WIN)
604// static
605std::vector<uint8_t> EmbedderTest::RenderPageWithFlagsToEmf(FPDF_PAGE page,
606 int flags) {
607 HDC dc = CreateEnhMetaFileA(nullptr, nullptr, nullptr, nullptr);
608
609 int width = static_cast<int>(FPDF_GetPageWidthF(page));
610 int height = static_cast<int>(FPDF_GetPageHeightF(page));
611 HRGN rgn = CreateRectRgn(0, 0, width, height);
612 SelectClipRgn(dc, rgn);
613 DeleteObject(rgn);
614
615 SelectObject(dc, GetStockObject(NULL_PEN));
616 SelectObject(dc, GetStockObject(WHITE_BRUSH));
617 // If a PS_NULL pen is used, the dimensions of the rectangle are 1 pixel less.
618 Rectangle(dc, 0, 0, width + 1, height + 1);
619
620 FPDF_RenderPage(dc, page, 0, 0, width, height, 0, flags);
621
622 HENHMETAFILE emf = CloseEnhMetaFile(dc);
623 UINT size_in_bytes = GetEnhMetaFileBits(emf, 0, nullptr);
624 std::vector<uint8_t> buffer(size_in_bytes);
625 GetEnhMetaFileBits(emf, size_in_bytes, buffer.data());
626 DeleteEnhMetaFile(emf);
627 return buffer;
628}
629
630// static
631std::string EmbedderTest::GetPostScriptFromEmf(
632 pdfium::span<const uint8_t> emf_data) {
633 // This comes from Emf::InitFromData() in Chromium.
634 HENHMETAFILE emf = SetEnhMetaFileBits(
635 pdfium::base::checked_cast<UINT>(emf_data.size()), emf_data.data());
636 if (!emf)
637 return std::string();
638
639 // This comes from Emf::Enumerator::Enumerator() in Chromium.
640 std::vector<const ENHMETARECORD*> records;
641 if (!EnumEnhMetaFile(nullptr, emf, &GetRecordProc, &records, nullptr)) {
642 DeleteEnhMetaFile(emf);
643 return std::string();
644 }
645
646 // This comes from PostScriptMetaFile::SafePlayback() in Chromium.
647 std::string ps_data;
648 for (const auto* record : records) {
649 if (record->iType != EMR_GDICOMMENT)
650 continue;
651
652 // PostScript data is encapsulated inside EMF comment records.
653 // The first two bytes of the comment indicate the string length. The rest
654 // is the actual string data.
655 const auto* comment = reinterpret_cast<const EMRGDICOMMENT*>(record);
656 const char* data = reinterpret_cast<const char*>(comment->Data);
657 uint16_t size = *reinterpret_cast<const uint16_t*>(data);
658 data += 2;
659 ps_data.append(data, size);
660 }
661 DeleteEnhMetaFile(emf);
662 return ps_data;
663}
664#endif // BUILDFLAG(IS_WIN)
665
668}
669
670// static
672 switch (format) {
673 case FPDFBitmap_Gray:
674 return 1;
675 case FPDFBitmap_BGR:
676 return 3;
677 case FPDFBitmap_BGRx:
678 case FPDFBitmap_BGRA:
679 return 4;
680 default:
681 NOTREACHED_NORETURN();
682 }
683}
684
686 const char* password) {
687 memset(&saved_file_access_, 0, sizeof(saved_file_access_));
688 saved_file_access_.m_FileLen =
689 pdfium::base::checked_cast<unsigned long>(data_string_.size());
690 saved_file_access_.m_GetBlock = GetBlockFromString;
691 // Copy data to prevent clearing it before saved document close.
692 saved_document_file_data_ = data_string_;
693 saved_file_access_.m_Param = &saved_document_file_data_;
694
695 saved_fake_file_access_ =
696 std::make_unique<FakeFileAccess>(&saved_file_access_);
697
698 EXPECT_TRUE(OpenDocumentHelper(
699 password, LinearizeOption::kDefaultLinearize,
700 JavaScriptOption::kEnableJavaScript, saved_fake_file_access_.get(),
701 &saved_document_, &saved_avail_, &saved_form_handle_));
702 return saved_document();
703}
704
706 DCHECK(saved_document());
707
708 saved_form_handle_.reset();
709 saved_document_.reset();
710 saved_avail_.reset();
711}
712
713FPDF_PAGE EmbedderTest::LoadSavedPage(int page_number) {
714 DCHECK(saved_form_handle());
715 DCHECK(page_number >= 0);
716 DCHECK(!pdfium::Contains(saved_page_map_, page_number));
717
718 FPDF_PAGE page = FPDF_LoadPage(saved_document(), page_number);
719 if (!page)
720 return nullptr;
721
724 saved_page_map_[page_number] = page;
725 return page;
726}
727
728void EmbedderTest::CloseSavedPage(FPDF_PAGE page) {
729 DCHECK(saved_form_handle());
730
731 int page_number = GetPageNumberForSavedPage(page);
732 CHECK_GE(page_number, 0);
733
737
738 saved_page_map_.erase(page_number);
739}
740
742 int width,
743 int height,
744 const char* md5) {
745 DCHECK(saved_document());
746 DCHECK(page);
747
748 ScopedFPDFBitmap bitmap = RenderSavedPageWithFlags(page, FPDF_ANNOT);
749 CompareBitmap(bitmap.get(), width, height, md5);
750}
751
752void EmbedderTest::VerifySavedDocument(int width, int height, const char* md5) {
753 ASSERT_TRUE(OpenSavedDocument());
754 FPDF_PAGE page = LoadSavedPage(0);
755 VerifySavedRendering(page, width, height, md5);
758}
759
761 DCHECK(fake_file_access_);
762 fake_file_access_->SetWholeFileAvailable();
763}
764
766 document_.reset(FPDFAvail_GetDocument(avail(), nullptr));
767}
768
769void EmbedderTest::CreateAvail(FX_FILEAVAIL* file_avail,
770 FPDF_FILEACCESS* file) {
771 avail_.reset(FPDFAvail_Create(file_avail, file));
772}
773
774FPDF_PAGE EmbedderTest::Delegate::GetPage(FPDF_FORMFILLINFO* info,
775 FPDF_DOCUMENT document,
776 int page_index) {
777 EmbedderTest* test = static_cast<EmbedderTest*>(info);
778 auto it = test->page_map_.find(page_index);
779 return it != test->page_map_.end() ? it->second : nullptr;
780}
781
782// static
783std::string EmbedderTest::HashBitmap(FPDF_BITMAP bitmap) {
784 int stride = FPDFBitmap_GetStride(bitmap);
785 int usable_bytes_per_row =
786 GetBitmapBytesPerPixel(bitmap) * FPDFBitmap_GetWidth(bitmap);
787 int height = FPDFBitmap_GetHeight(bitmap);
788 auto span =
789 pdfium::make_span(static_cast<uint8_t*>(FPDFBitmap_GetBuffer(bitmap)),
790 static_cast<size_t>(stride) * height);
791
793 for (int i = 0; i < height; ++i)
794 CRYPT_MD5Update(&context, span.subspan(i * stride, usable_bytes_per_row));
795 uint8_t digest[16];
796 CRYPT_MD5Finish(&context, digest);
797 return CryptToBase16(digest);
798}
799
800// static
801void EmbedderTest::WriteBitmapToPng(FPDF_BITMAP bitmap,
802 const std::string& filename) {
804}
805
806// static
807void EmbedderTest::CompareBitmap(FPDF_BITMAP bitmap,
808 int expected_width,
809 int expected_height,
810 const char* expected_md5sum) {
811 ASSERT_EQ(expected_width, FPDFBitmap_GetWidth(bitmap));
812 ASSERT_EQ(expected_height, FPDFBitmap_GetHeight(bitmap));
813
814 // The expected stride is calculated using the same formula as in
815 // CFX_DIBitmap::CalculatePitchAndSize(), which sets the bitmap stride.
816 const int expected_stride =
817 (expected_width * GetBitmapBytesPerPixel(bitmap) * 8 + 31) / 32 * 4;
818 ASSERT_EQ(expected_stride, FPDFBitmap_GetStride(bitmap));
819
820 if (!expected_md5sum)
821 return;
822
823 std::string actual_md5sum = HashBitmap(bitmap);
824 EXPECT_EQ(expected_md5sum, actual_md5sum);
826 WriteBitmapToPng(bitmap, actual_md5sum + ".png");
827 }
828}
829
830// static
831int EmbedderTest::WriteBlockCallback(FPDF_FILEWRITE* pFileWrite,
832 const void* data,
833 unsigned long size) {
834 EmbedderTest* pThis = static_cast<EmbedderTest*>(pFileWrite);
835
836 pThis->data_string_.append(static_cast<const char*>(data), size);
837
838 if (pThis->filestream_.is_open())
839 pThis->filestream_.write(static_cast<const char*>(data), size);
840
841 return 1;
842}
843
844// static
846 unsigned long pos,
847 unsigned char* buf,
848 unsigned long size) {
849 std::string* new_file = static_cast<std::string*>(param);
850 CHECK(new_file);
851
852 pdfium::base::CheckedNumeric<size_t> end = pos;
853 end += size;
854 CHECK_LE(end.ValueOrDie(), new_file->size());
855
856 memcpy(buf, new_file->data() + pos, size);
857 return 1;
858}
859
860// static
861int EmbedderTest::GetPageNumberForPage(const PageNumberToHandleMap& page_map,
862 FPDF_PAGE page) {
863 for (const auto& it : page_map) {
864 if (it.second == page) {
865 int page_number = it.first;
866 DCHECK(page_number >= 0);
867 return page_number;
868 }
869 }
870 return -1;
871}
872
873int EmbedderTest::GetPageNumberForLoadedPage(FPDF_PAGE page) const {
874 return GetPageNumberForPage(page_map_, page);
875}
876
877int EmbedderTest::GetPageNumberForSavedPage(FPDF_PAGE page) const {
878 return GetPageNumberForPage(saved_page_map_, page);
879}
880
881#ifndef NDEBUG
882void EmbedderTest::OpenPDFFileForWrite(const std::string& filename) {
883 filestream_.open(filename, std::ios_base::binary);
884}
885
887 filestream_.close();
888}
889#endif
static void WriteBitmapToPng(FPDF_BITMAP bitmap, const std::string &filename)
static EmbedderTestEnvironment * GetInstance()
virtual void UnsupportedHandler(int type)
virtual void DoGoToAction(FPDF_FORMFILLINFO *info, int page_index, int zoom_mode, float *pos_arry, int array_size)
virtual int SetTimer(int msecs, TimerCallback fn)
virtual int Alert(FPDF_WIDESTRING message, FPDF_WIDESTRING title, int type, int icon)
virtual void DoURIAction(FPDF_BYTESTRING uri)
virtual FPDF_PAGE GetPage(FPDF_FORMFILLINFO *info, FPDF_DOCUMENT document, int page_index)
virtual void KillTimer(int id)
virtual void OnFocusChange(FPDF_FORMFILLINFO *info, FPDF_ANNOTATION annot, int page_index)
virtual void DoURIActionWithKeyboardModifier(FPDF_FORMFILLINFO *info, FPDF_BYTESTRING uri, int modifiers)
ScopedFPDFBitmap RenderLoadedPage(FPDF_PAGE page)
void SetUp() override
virtual ~EmbedderTest()
ScopedFPDFBitmap RenderLoadedPageWithFlags(FPDF_PAGE page, int flags)
void SetWholeFileAvailable()
void VerifySavedDocument(int width, int height, const char *md5)
FPDF_DOCUMENT OpenSavedDocumentWithPassword(const char *password)
void VerifySavedRendering(FPDF_PAGE page, int width, int height, const char *md5)
void SetInitialFormFieldHighlight(FPDF_FORMHANDLE form)
FPDF_DOCUMENT saved_document() const
void CloseSavedDocument()
FPDF_DOCUMENT OpenSavedDocument()
ScopedFPDFBitmap RenderSavedPageWithFlags(FPDF_PAGE page, int flags)
FPDF_FORMHANDLE SetupFormFillEnvironment(FPDF_DOCUMENT doc, JavaScriptOption javascript_option)
void TearDown() override
FPDF_FORMHANDLE saved_form_handle() const
FPDF_PAGE LoadPageNoEvents(int page_number)
static void CompareBitmap(FPDF_BITMAP bitmap, int expected_width, int expected_height, const char *expected_md5sum)
void UnloadPage(FPDF_PAGE page)
bool OpenDocumentHelper(const char *password, LinearizeOption linearize_option, JavaScriptOption javascript_option, FakeFileAccess *network_simulator, ScopedFPDFDocument *document, ScopedFPDFAvail *avail, ScopedFPDFFormHandle *form_handle)
void ClosePDFFileForWrite()
static int GetBlockFromString(void *param, unsigned long pos, unsigned char *buf, unsigned long size)
FPDF_DOCUMENT document() const
ScopedFPDFBitmap RenderSavedPage(FPDF_PAGE page)
Delegate * GetDelegate()
void UnloadPageNoEvents(FPDF_PAGE page)
void CreateAvail(FX_FILEAVAIL *file_avail, FPDF_FILEACCESS *file)
void CloseSavedPage(FPDF_PAGE page)
FPDF_PAGE LoadPage(int page_number)
static std::string HashBitmap(FPDF_BITMAP bitmap)
void SetDocumentFromAvail()
FPDF_PAGE LoadSavedPage(int page_number)
FPDF_FORMHANDLE form_handle() const
static int BytesPerPixelForFormat(int format)
void CreateEmptyDocument()
void CreateEmptyDocumentWithoutFormFillEnvironment()
FX_DOWNLOADHINTS * GetDownloadHints() const
FX_FILEAVAIL * GetFileAvail() const
FPDF_FILEACCESS * GetFileAccess() const
static int GetBlock(void *param, unsigned long pos, unsigned char *pBuf, unsigned long size)
#define PDF_DATA_NOTAVAIL
#define PDF_DATA_ERROR
FPDF_EXPORT int FPDF_CALLCONV FPDFAvail_IsFormAvail(FPDF_AVAIL avail, FX_DOWNLOADHINTS *hints)
#define PDF_LINEARIZED
#define PDF_FORM_ERROR
FPDF_EXPORT int FPDF_CALLCONV FPDFAvail_IsPageAvail(FPDF_AVAIL avail, int page_index, FX_DOWNLOADHINTS *hints)
FPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV FPDFAvail_GetDocument(FPDF_AVAIL avail, FPDF_BYTESTRING password)
FPDF_EXPORT int FPDF_CALLCONV FPDFAvail_IsDocAvail(FPDF_AVAIL avail, FX_DOWNLOADHINTS *hints)
FPDF_EXPORT int FPDF_CALLCONV FPDFAvail_GetFirstPageNum(FPDF_DOCUMENT doc)
FPDF_EXPORT int FPDF_CALLCONV FPDFAvail_IsLinearized(FPDF_AVAIL avail)
FPDF_EXPORT FPDF_AVAIL FPDF_CALLCONV FPDFAvail_Create(FX_FILEAVAIL *file_avail, FPDF_FILEACCESS *file)
FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_HasTransparency(FPDF_PAGE page)
FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FSDK_SetUnSpObjProcessHandler(UNSUPPORT_INFO *unsp_info)
Definition fpdf_ext.cpp:67
#define FPDFDOC_AACTION_WC
FPDF_EXPORT void FPDF_CALLCONV FORM_OnAfterLoadPage(FPDF_PAGE page, FPDF_FORMHANDLE hHandle)
FPDF_EXPORT void FPDF_CALLCONV FPDF_SetFormFieldHighlightAlpha(FPDF_FORMHANDLE hHandle, unsigned char alpha)
FPDF_EXPORT void FPDF_CALLCONV FORM_OnBeforeClosePage(FPDF_PAGE page, FPDF_FORMHANDLE hHandle)
#define FORMTYPE_XFA_FOREGROUND
void(* TimerCallback)(int idEvent)
#define FPDFPAGE_AACTION_CLOSE
FPDF_EXPORT void FPDF_CALLCONV FORM_DoPageAAction(FPDF_PAGE page, FPDF_FORMHANDLE hHandle, int aaType)
#define FPDF_FORMFIELD_UNKNOWN
FPDF_EXPORT void FPDF_CALLCONV FORM_DoDocumentJSAction(FPDF_FORMHANDLE hHandle)
#define FORMTYPE_XFA_FULL
FPDF_EXPORT void FPDF_CALLCONV FORM_DoDocumentOpenAction(FPDF_FORMHANDLE hHandle)
FPDF_EXPORT void FPDF_CALLCONV FORM_DoDocumentAAction(FPDF_FORMHANDLE hHandle, int aaType)
FPDF_EXPORT void FPDF_CALLCONV FPDF_SetFormFieldHighlightColor(FPDF_FORMHANDLE hHandle, int fieldType, unsigned long color)
FPDF_EXPORT FPDF_FORMHANDLE FPDF_CALLCONV FPDFDOC_InitFormFillEnvironment(FPDF_DOCUMENT document, FPDF_FORMFILLINFO *formInfo)
#define FPDFPAGE_AACTION_OPEN
FPDF_EXPORT int FPDF_CALLCONV FPDF_GetFormType(FPDF_DOCUMENT document)
FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_LoadXFA(FPDF_DOCUMENT document)
FPDF_EXPORT FPDF_PAGE FPDF_CALLCONV FPDF_LoadPage(FPDF_DOCUMENT document, int page_index)
FPDF_EXPORT int FPDF_CALLCONV FPDF_GetPageCount(FPDF_DOCUMENT document)
FPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV FPDF_LoadCustomDocument(FPDF_FILEACCESS *pFileAccess, FPDF_BYTESTRING password)
FPDF_EXPORT int FPDF_CALLCONV FPDFBitmap_GetHeight(FPDF_BITMAP bitmap)
FPDF_EXPORT float FPDF_CALLCONV FPDF_GetPageHeightF(FPDF_PAGE page)
FPDF_EXPORT int FPDF_CALLCONV FPDFBitmap_GetStride(FPDF_BITMAP bitmap)
FPDF_EXPORT int FPDF_CALLCONV FPDFBitmap_GetFormat(FPDF_BITMAP bitmap)
FPDF_EXPORT void *FPDF_CALLCONV FPDFBitmap_GetBuffer(FPDF_BITMAP bitmap)
FPDF_EXPORT int FPDF_CALLCONV FPDFBitmap_GetWidth(FPDF_BITMAP bitmap)
FPDF_EXPORT float FPDF_CALLCONV FPDF_GetPageWidthF(FPDF_PAGE page)
FPDF_EXPORT void FPDF_CALLCONV FPDF_ClosePage(FPDF_PAGE page)
#define FPDFBitmap_BGR
Definition fpdfview.h:1100
#define FPDFBitmap_BGRx
Definition fpdfview.h:1102
#define FPDFBitmap_BGRA
Definition fpdfview.h:1104
#define FPDFBitmap_Gray
Definition fpdfview.h:1098
#define FPDF_ANNOT
Definition fpdfview.h:804
void CRYPT_MD5Finish(CRYPT_md5_context *context, uint8_t digest[16])
Definition fx_crypt.cpp:214
CRYPT_md5_context CRYPT_MD5Start()
Definition fx_crypt.cpp:176
#define CHECK(cvref)
int(* WriteBlock)(struct FPDF_FILEWRITE_ *pThis, const void *pData, unsigned long size)
Definition fpdf_save.h:39
int(* FFI_SetTimer)(struct _FPDF_FORMFILLINFO *pThis, int uElapse, TimerCallback lpTimerFunc)
void(* FFI_Invalidate)(struct _FPDF_FORMFILLINFO *pThis, FPDF_PAGE page, double left, double top, double right, double bottom)
void(* FFI_KillTimer)(struct _FPDF_FORMFILLINFO *pThis, int nTimerID)
void(* FFI_SetCursor)(struct _FPDF_FORMFILLINFO *pThis, int nCursorType)
void(* FFI_DoGoToAction)(struct _FPDF_FORMFILLINFO *pThis, int nPageIndex, int zoomMode, float *fPosArray, int sizeofArray)
void(* FFI_DoURIAction)(struct _FPDF_FORMFILLINFO *pThis, FPDF_BYTESTRING bsURI)
void(* FFI_OnFocusChange)(struct _FPDF_FORMFILLINFO *param, FPDF_ANNOTATION annot, int page_index)
IPDF_JSPLATFORM * m_pJsPlatform
void(* FFI_SetTextFieldFocus)(struct _FPDF_FORMFILLINFO *pThis, FPDF_WIDESTRING value, FPDF_DWORD valueLen, FPDF_BOOL is_focus)
void(* FFI_OutputSelectedRect)(struct _FPDF_FORMFILLINFO *pThis, FPDF_PAGE page, double left, double top, double right, double bottom)
int(* FFI_GetRotation)(struct _FPDF_FORMFILLINFO *pThis, FPDF_PAGE page)
void(* FFI_DoURIActionWithKeyboardModifier)(struct _FPDF_FORMFILLINFO *param, FPDF_BYTESTRING uri, int modifiers)
void(* FFI_ExecuteNamedAction)(struct _FPDF_FORMFILLINFO *pThis, FPDF_BYTESTRING namedAction)
void(* FFI_OnChange)(struct _FPDF_FORMFILLINFO *pThis)
int(* app_alert)(struct _IPDF_JsPlatform *pThis, FPDF_WIDESTRING Msg, FPDF_WIDESTRING Title, int Type, int Icon)
void(* FSDK_UnSupport_Handler)(struct _UNSUPPORT_INFO *pThis, int nType)
Definition fpdf_ext.h:61