#ifndef TESTING_EMBEDDER_TEST_H_
#define TESTING_EMBEDDER_TEST_H_
#include <stdint.h>
#include <fstream>
#include <map>
#include <memory>
#include <string>
#include <vector>
#include "build/build_config.h"
#include "core/fxcrt/span.h"
#include "core/fxcrt/unowned_ptr.h"
#include "public/cpp/fpdf_scopers.h"
#include "public/fpdf_dataavail.h"
#include "public/fpdf_ext.h"
#include "public/fpdf_formfill.h"
#include "public/fpdf_save.h"
#include "public/fpdfview.h"
#include "testing/fake_file_access.h"
#include "testing/gtest/include/gtest/gtest.h"
class TestLoader;
class EmbedderTest : public ::testing::Test,
public UNSUPPORT_INFO,
public IPDF_JSPLATFORM,
public FPDF_FORMFILLINFO,
public FPDF_FILEWRITE {
public:
enum class LinearizeOption { kDefaultLinearize, kMustLinearize };
enum class JavaScriptOption { kDisableJavaScript, kEnableJavaScript };
class Delegate {
public:
virtual ~Delegate() = default;
virtual void UnsupportedHandler(int type) {}
virtual int Alert(FPDF_WIDESTRING message,
FPDF_WIDESTRING title,
int type,
int icon) {
return 0;
}
virtual int SetTimer(int msecs, TimerCallback fn) { return 0; }
virtual void KillTimer(int id) {}
virtual FPDF_PAGE GetPage(FPDF_FORMFILLINFO* info,
FPDF_DOCUMENT document,
int page_index);
virtual void DoURIAction(FPDF_BYTESTRING uri) {}
virtual void DoGoToAction(FPDF_FORMFILLINFO* info,
int page_index,
int zoom_mode,
float* pos_arry,
int array_size) {}
virtual void OnFocusChange(FPDF_FORMFILLINFO* info,
FPDF_ANNOTATION annot,
int page_index) {}
virtual void DoURIActionWithKeyboardModifier(FPDF_FORMFILLINFO* info,
FPDF_BYTESTRING uri,
int modifiers) {}
};
class ScopedSavedDoc {
public:
ScopedSavedDoc();
explicit ScopedSavedDoc(EmbedderTest* test);
ScopedSavedDoc(const ScopedSavedDoc&) = delete;
ScopedSavedDoc& operator=(const ScopedSavedDoc&) = delete;
ScopedSavedDoc(ScopedSavedDoc&&) noexcept;
ScopedSavedDoc& operator=(ScopedSavedDoc&&) noexcept;
~ScopedSavedDoc();
FPDF_DOCUMENT get() { return doc_; }
explicit operator bool() const { return !!doc_; }
private:
UnownedPtr<EmbedderTest> test_;
FPDF_DOCUMENT doc_;
};
class ScopedPageBase {
public:
FPDF_PAGE get() { return page_; }
explicit operator bool() const { return !!page_; }
protected:
ScopedPageBase(EmbedderTest* test, FPDF_PAGE page);
~ScopedPageBase();
UnownedPtr<EmbedderTest> test_;
FPDF_PAGE page_;
};
class ScopedPage : public ScopedPageBase {
public:
ScopedPage();
ScopedPage(EmbedderTest* test, int page_index);
ScopedPage(const ScopedPage&) = delete;
ScopedPage& operator=(const ScopedPage&) = delete;
ScopedPage(ScopedPage&&) noexcept;
ScopedPage& operator=(ScopedPage&&) noexcept;
~ScopedPage();
};
class ScopedSavedPage : public ScopedPageBase {
public:
ScopedSavedPage();
ScopedSavedPage(EmbedderTest* test, int page_index);
ScopedSavedPage(const ScopedSavedPage&) = delete;
ScopedSavedPage& operator=(const ScopedSavedPage&) = delete;
ScopedSavedPage(ScopedSavedPage&&) noexcept;
ScopedSavedPage& operator=(ScopedSavedPage&&) noexcept;
~ScopedSavedPage();
};
EmbedderTest();
~EmbedderTest() override;
void SetUp() override;
void TearDown() override;
Delegate* GetDelegate() { return delegate_; }
void SetDelegate(Delegate* delegate) {
delegate_ = delegate ? delegate : default_delegate_.get();
}
void SetFormFillInfoVersion(int form_fill_info_version) {
form_fill_info_version_ = form_fill_info_version;
}
void SetDocumentFromAvail();
FPDF_DOCUMENT document() const { return document_.get(); }
FPDF_DOCUMENT saved_document() const { return saved_document_.get(); }
FPDF_FORMHANDLE form_handle() const { return form_handle_.get(); }
FPDF_FORMHANDLE saved_form_handle() const { return saved_form_handle_.get(); }
void CreateAvail(FX_FILEAVAIL* file_avail, FPDF_FILEACCESS* file);
FPDF_AVAIL avail() { return avail_.get(); }
void CreateEmptyDocument();
void CreateEmptyDocumentWithoutFormFillEnvironment();
virtual bool OpenDocumentWithOptions(const std::string& filename,
const char* password,
LinearizeOption linearize_option,
JavaScriptOption javascript_option);
bool OpenDocument(const std::string& filename);
bool OpenDocumentLinearized(const std::string& filename);
bool OpenDocumentWithPassword(const std::string& filename,
const char* password);
bool OpenDocumentWithoutJavaScript(const std::string& filename);
void CloseDocument();
void DoOpenActions();
int GetFirstPageNum();
int GetPageCount();
ScopedPage LoadScopedPage(int page_index);
FPDF_PAGE LoadPage(int page_index);
FPDF_PAGE LoadPageNoEvents(int page_index);
void UnloadPage(FPDF_PAGE page);
void UnloadPageNoEvents(FPDF_PAGE page);
void SetInitialFormFieldHighlight(FPDF_FORMHANDLE form);
ScopedFPDFBitmap RenderLoadedPage(FPDF_PAGE page);
ScopedFPDFBitmap RenderLoadedPageWithFlags(FPDF_PAGE page, int flags);
ScopedFPDFBitmap RenderSavedPage(FPDF_PAGE page);
ScopedFPDFBitmap RenderSavedPageWithFlags(FPDF_PAGE page, int flags);
static ScopedFPDFBitmap RenderPageWithFlags(FPDF_PAGE page,
FPDF_FORMHANDLE handle,
int flags);
static ScopedFPDFBitmap RenderPage(FPDF_PAGE page);
#if BUILDFLAG(IS_WIN)
static std::vector<uint8_t> RenderPageWithFlagsToEmf(FPDF_PAGE page,
int flags);
static std::string GetPostScriptFromEmf(pdfium::span<const uint8_t> emf_data);
#endif
static int BytesPerPixelForFormat(int format);
protected:
using PageNumberToHandleMap = std::map<int, FPDF_PAGE>;
bool OpenDocumentHelper(const char* password,
LinearizeOption linearize_option,
JavaScriptOption javascript_option,
FakeFileAccess* network_simulator,
ScopedFPDFDocument* document,
ScopedFPDFAvail* avail,
ScopedFPDFFormHandle* form_handle);
FPDF_FORMHANDLE SetupFormFillEnvironment(FPDF_DOCUMENT doc,
JavaScriptOption javascript_option);
static std::string HashBitmap(FPDF_BITMAP bitmap);
static void WriteBitmapToPng(FPDF_BITMAP bitmap, const std::string& filename);
static void CompareBitmap(FPDF_BITMAP bitmap,
int expected_width,
int expected_height,
const char* expected_md5sum);
void ClearString() { data_string_.clear(); }
const std::string& GetString() const { return data_string_; }
static int GetBlockFromString(void* param,
unsigned long pos,
unsigned char* buf,
unsigned long size);
ScopedSavedDoc OpenScopedSavedDocument();
FPDF_DOCUMENT OpenSavedDocument();
FPDF_DOCUMENT OpenSavedDocumentWithPassword(const char* password);
void CloseSavedDocument();
ScopedSavedPage LoadScopedSavedPage(int page_index);
FPDF_PAGE LoadSavedPage(int page_index);
void CloseSavedPage(FPDF_PAGE page);
void VerifySavedRendering(FPDF_PAGE page,
int width,
int height,
const char* md5);
void VerifySavedDocument(int width, int height, const char* md5);
void SetWholeFileAvailable();
#ifndef NDEBUG
void OpenPDFFileForWrite(const std::string& filename);
void ClosePDFFileForWrite();
#endif
private:
static int WriteBlockCallback(FPDF_FILEWRITE* pFileWrite,
const void* data,
unsigned long size);
static int GetPageNumberForPage(const PageNumberToHandleMap& page_map,
FPDF_PAGE page);
int GetPageNumberForLoadedPage(FPDF_PAGE page) const;
int GetPageNumberForSavedPage(FPDF_PAGE page) const;
void UnloadPageCommon(FPDF_PAGE page, bool do_events);
FPDF_PAGE LoadPageCommon(int page_index, bool do_events);
std::unique_ptr<Delegate> default_delegate_;
Delegate* delegate_;
#ifdef PDF_ENABLE_XFA
int form_fill_info_version_ = 2;
#else
int form_fill_info_version_ = 1;
#endif
std::vector<uint8_t> file_contents_;
std::unique_ptr<TestLoader> loader_;
FPDF_FILEACCESS file_access_;
std::unique_ptr<FakeFileAccess> fake_file_access_;
ScopedFPDFAvail avail_;
ScopedFPDFDocument document_;
ScopedFPDFFormHandle form_handle_;
PageNumberToHandleMap page_map_;
FPDF_FILEACCESS saved_file_access_;
std::unique_ptr<FakeFileAccess> saved_fake_file_access_;
ScopedFPDFAvail saved_avail_;
ScopedFPDFDocument saved_document_;
ScopedFPDFFormHandle saved_form_handle_;
PageNumberToHandleMap saved_page_map_;
std::string data_string_;
std::string saved_document_file_data_;
std::ofstream filestream_;
};
#endif