From 96d1334cb605aab143d3135da4d4550920735e91 Mon Sep 17 00:00:00 2001 From: Tom Sepez Date: Fri, 16 Jan 2015 14:59:26 -0800 Subject: Merge to XFA: PDFium embeddertests. This consists of two origin/master CLs: Review URL: https://codereview.chromium.org/857483005 Review URL: https://codereview.chromium.org/827733006 It also fixes a couple of segv's in XFA when the library is initialized and destroyed multiple times in the same process. R=jam@chromium.org TBR=jam@chromium.org Review URL: https://codereview.chromium.org/856623004 --- testing/embedder_test.cpp | 309 ++++++++++++++++++++++++++++++++++++++ testing/embedder_test.h | 82 ++++++++++ testing/resources/about_blank.pdf | Bin 0 -> 735 bytes 3 files changed, 391 insertions(+) create mode 100644 testing/embedder_test.cpp create mode 100644 testing/embedder_test.h create mode 100644 testing/resources/about_blank.pdf (limited to 'testing') diff --git a/testing/embedder_test.cpp b/testing/embedder_test.cpp new file mode 100644 index 0000000000..539f48cff5 --- /dev/null +++ b/testing/embedder_test.cpp @@ -0,0 +1,309 @@ +// Copyright (c) 2015 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "embedder_test.h" + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "../fpdfsdk/include/fpdf_ext.h" +#include "../fpdfsdk/include/fpdftext.h" +#include "../fpdfsdk/include/fpdfview.h" +#include "../core/include/fxcrt/fx_system.h" +#include "v8/include/v8.h" + +#ifdef _WIN32 +#define snprintf _snprintf +#define PATH_SEPARATOR '\\' +#else +#define PATH_SEPARATOR '/' +#endif + +namespace { + +// Reads the entire contents of a file into a newly malloc'd buffer. +static char* GetFileContents(const char* filename, size_t* retlen) { + FILE* file = fopen(filename, "rb"); + if (!file) { + fprintf(stderr, "Failed to open: %s\n", filename); + return NULL; + } + (void) fseek(file, 0, SEEK_END); + size_t file_length = ftell(file); + if (!file_length) { + return NULL; + } + (void) fseek(file, 0, SEEK_SET); + char* buffer = (char*) malloc(file_length); + if (!buffer) { + return NULL; + } + size_t bytes_read = fread(buffer, 1, file_length, file); + (void) fclose(file); + if (bytes_read != file_length) { + fprintf(stderr, "Failed to read: %s\n", filename); + free(buffer); + return NULL; + } + *retlen = bytes_read; + return buffer; +} + +#ifdef V8_USE_EXTERNAL_STARTUP_DATA +// Returns the full path for an external V8 data file based on either +// the currect exectuable path or an explicit override. +static std::string GetFullPathForSnapshotFile(const Options& options, + const std::string& filename) { + std::string result; + if (!options.bin_directory.empty()) { + result = options.bin_directory; + if (*options.bin_directory.rbegin() != PATH_SEPARATOR) { + result += PATH_SEPARATOR; + } + } else if (!options.exe_path.empty()) { + size_t last_separator = options.exe_path.rfind(PATH_SEPARATOR); + if (last_separator != std::string::npos) { + result = options.exe_path.substr(0, last_separator + 1); + } + } + result += filename; + return result; +} + +// Reads an extenal V8 data file from the |options|-indicated location, +// returing true on success and false on error. +static bool GetExternalData(const Options& options, + const std::string& bin_filename, + v8::StartupData* result_data) { + std::string full_path = GetFullPathForSnapshotFile(options, bin_filename); + size_t data_length = 0; + char* data_buffer = GetFileContents(full_path.c_str(), &data_length); + if (!data_buffer) { + return false; + } + result_data->data = const_cast(data_buffer); + result_data->raw_size = data_length; + return true; +} +#endif // V8_USE_EXTERNAL_STARTUP_DATA + +} // namespace + +int Form_Alert(IPDF_JSPLATFORM*, FPDF_WIDESTRING, FPDF_WIDESTRING, int, int) { + printf("Form_Alert called.\n"); + return 0; +} + +void Unsupported_Handler(UNSUPPORT_INFO*, int type) { + std::string feature = "Unknown"; + switch (type) { + case FPDF_UNSP_DOC_XFAFORM: + feature = "XFA"; + break; + case FPDF_UNSP_DOC_PORTABLECOLLECTION: + feature = "Portfolios_Packages"; + break; + case FPDF_UNSP_DOC_ATTACHMENT: + case FPDF_UNSP_ANNOT_ATTACHMENT: + feature = "Attachment"; + break; + case FPDF_UNSP_DOC_SECURITY: + feature = "Rights_Management"; + break; + case FPDF_UNSP_DOC_SHAREDREVIEW: + feature = "Shared_Review"; + break; + case FPDF_UNSP_DOC_SHAREDFORM_ACROBAT: + case FPDF_UNSP_DOC_SHAREDFORM_FILESYSTEM: + case FPDF_UNSP_DOC_SHAREDFORM_EMAIL: + feature = "Shared_Form"; + break; + case FPDF_UNSP_ANNOT_3DANNOT: + feature = "3D"; + break; + case FPDF_UNSP_ANNOT_MOVIE: + feature = "Movie"; + break; + case FPDF_UNSP_ANNOT_SOUND: + feature = "Sound"; + break; + case FPDF_UNSP_ANNOT_SCREEN_MEDIA: + case FPDF_UNSP_ANNOT_SCREEN_RICHMEDIA: + feature = "Screen"; + break; + case FPDF_UNSP_ANNOT_SIG: + feature = "Digital_Signature"; + break; + } + printf("Unsupported feature: %s.\n", feature.c_str()); +} + +class TestLoader { + public: + TestLoader(const char* pBuf, size_t len); + + const char* m_pBuf; + size_t m_Len; +}; + +TestLoader::TestLoader(const char* pBuf, size_t len) + : m_pBuf(pBuf), m_Len(len) { +} + +int Get_Block(void* param, unsigned long pos, unsigned char* pBuf, + unsigned long size) { + TestLoader* pLoader = (TestLoader*) param; + if (pos + size < pos || pos + size > pLoader->m_Len) return 0; + memcpy(pBuf, pLoader->m_pBuf + pos, size); + return 1; +} + +bool Is_Data_Avail(FX_FILEAVAIL* pThis, size_t offset, size_t size) { + return true; +} + +void Add_Segment(FX_DOWNLOADHINTS* pThis, size_t offset, size_t size) { +} + +void EmbedderTest::SetUp() { + v8::V8::InitializeICU(); + +#ifdef V8_USE_EXTERNAL_STARTUP_DATA + ASSERT_TRUE(GetExternalData(options, "natives_blob.bin", &natives_)); + ASSERT_TRUE(GetExternalData(options, "snapshot_blob.bin", &snapshot_)); + v8::V8::SetNativesDataBlob(&natives); + v8::V8::SetSnapshotDataBlob(&snapshot); +#endif // V8_USE_EXTERNAL_STARTUP_DATA + + FPDF_InitLibrary(); + + UNSUPPORT_INFO unsuppored_info; + memset(&unsuppored_info, '\0', sizeof(unsuppored_info)); + unsuppored_info.version = 1; + unsuppored_info.FSDK_UnSupport_Handler = Unsupported_Handler; + FSDK_SetUnSpObjProcessHandler(&unsuppored_info); + } + +void EmbedderTest::TearDown() { + FPDF_CloseDocument(document_); + FPDFAvail_Destroy(avail_); + FPDF_DestroyLibrary(); + if (loader_) { + delete loader_; + } + if (file_contents_) { + free(file_contents_); + } +} + +bool EmbedderTest::OpenDocument(const std::string& filename) { + file_contents_ = GetFileContents(filename.c_str(), &file_length_); + if (!file_contents_) { + return false; + } + + loader_ = new TestLoader(file_contents_, file_length_); + file_access_.m_FileLen = static_cast(file_length_); + file_access_.m_GetBlock = Get_Block; + file_access_.m_Param = loader_; + + file_avail_.version = 1; + file_avail_.IsDataAvail = Is_Data_Avail; + + hints_.version = 1; + hints_.AddSegment = Add_Segment; + + avail_ = FPDFAvail_Create(&file_avail_, &file_access_); + (void) FPDFAvail_IsDocAvail(avail_, &hints_); + + if (!FPDFAvail_IsLinearized(avail_)) { + document_ = FPDF_LoadCustomDocument(&file_access_, NULL); + } else { + document_ = FPDFAvail_GetDocument(avail_, NULL); + } + if (!document_) { + return false; + } + (void) FPDF_LoadXFA(document_); + (void) FPDF_GetDocPermissions(document_); + (void) FPDFAvail_IsFormAvail(avail_, &hints_); + return true; +} + +FPDF_FORMHANDLE EmbedderTest::SetFormFillEnvironment() { + IPDF_JSPLATFORM platform_callbacks; + memset(&platform_callbacks, '\0', sizeof(platform_callbacks)); + platform_callbacks.version = 1; + platform_callbacks.app_alert = Form_Alert; + + FPDF_FORMFILLINFO form_callbacks; + memset(&form_callbacks, '\0', sizeof(form_callbacks)); + form_callbacks.version = 1; + form_callbacks.m_pJsPlatform = &platform_callbacks; + + FPDF_FORMHANDLE form = FPDFDOC_InitFormFillEnvironment(document_, + &form_callbacks); + FPDF_SetFormFieldHighlightColor(form, 0, 0xFFE4DD); + FPDF_SetFormFieldHighlightAlpha(form, 100); + return form; +} + +void EmbedderTest::ClearFormFillEnvironment(FPDF_FORMHANDLE form) { + FORM_DoDocumentAAction(form, FPDFDOC_AACTION_WC); + FPDFDOC_ExitFormFillEnvironment(form); +} + +void EmbedderTest::DoOpenActions(FPDF_FORMHANDLE form) { + FORM_DoDocumentJSAction(form); + FORM_DoDocumentOpenAction(form); +} + +int EmbedderTest::GetFirstPageNum() { + int first_page = FPDFAvail_GetFirstPageNum(document_); + (void) FPDFAvail_IsPageAvail(avail_, first_page, &hints_); + return first_page; +} + +int EmbedderTest::GetPageCount() { + int page_count = FPDF_GetPageCount(document_); + for (int i = 0; i < page_count; ++i) { + (void) FPDFAvail_IsPageAvail(avail_, i, &hints_); + } + return page_count; +} + +FPDF_PAGE EmbedderTest::LoadPage(int page_number, + FPDF_FORMHANDLE form) { + FPDF_PAGE page = FPDF_LoadPage(document_, page_number); + if (!page) { + return nullptr; + } + FORM_OnAfterLoadPage(page, form); + FORM_DoPageAAction(page, form, FPDFPAGE_AACTION_OPEN); + return page; +} + +FPDF_BITMAP EmbedderTest::RenderPage(FPDF_PAGE page, + FPDF_FORMHANDLE form) { + int width = static_cast(FPDF_GetPageWidth(page)); + int height = static_cast(FPDF_GetPageHeight(page)); + FPDF_BITMAP bitmap = FPDFBitmap_Create(width, height, 0); + FPDFBitmap_FillRect(bitmap, 0, 0, width, height, 0xFFFFFFFF); + FPDF_RenderPageBitmap(bitmap, page, 0, 0, width, height, 0, 0); + FPDF_FFLDraw(form, bitmap, page, 0, 0, width, height, 0, 0); + return bitmap; +} + +void EmbedderTest::UnloadPage(FPDF_PAGE page, FPDF_FORMHANDLE form) { + FORM_DoPageAAction(page, form, FPDFPAGE_AACTION_CLOSE); + FORM_OnBeforeClosePage(page, form); + FPDF_ClosePage(page); +} diff --git a/testing/embedder_test.h b/testing/embedder_test.h new file mode 100644 index 0000000000..48ea415e19 --- /dev/null +++ b/testing/embedder_test.h @@ -0,0 +1,82 @@ +// Copyright (c) 2015 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef TESTING_EMBEDDER_TEST_H_ +#define TESTING_EMBEDDER_TEST_H_ + +#include + +#include "../core/include/fxcrt/fx_system.h" +#include "../fpdfsdk/include/fpdf_dataavail.h" +#include "../fpdfsdk/include/fpdfformfill.h" +#include "../fpdfsdk/include/fpdfview.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "v8/include/v8.h" + +class TestLoader; + +// This class is used to load a PDF document, and then run programatic +// API tests against it. +class EmbedderTest : public ::testing::Test { + public: + EmbedderTest() : + document_(nullptr), + avail_(nullptr), + loader_(nullptr), + file_length_(0), + file_contents_(nullptr) { + memset(&hints_, 0, sizeof(hints_)); + memset(&file_access_, 0, sizeof(file_access_)); + memset(&file_avail_, 0, sizeof(file_avail_)); + } + + virtual ~EmbedderTest() { } + + void SetUp() override; + void TearDown() override; + + FPDF_DOCUMENT document() { return document_; } + + // Open the document specified by |filename|, or return false on failure. + virtual bool OpenDocument(const std::string& filename); + + // Create and return a handle to the form fill module for use with the + // FORM_ family of functions from fpdfformfill.h, or return NULL on failure. + virtual FPDF_FORMHANDLE SetFormFillEnvironment(); + + // Release the resources obtained from SetFormFillEnvironment(). + virtual void ClearFormFillEnvironment(FPDF_FORMHANDLE form); + + // Perform JavaScript actions that are to run at document open time. + virtual void DoOpenActions(FPDF_FORMHANDLE form); + + // Determine the page numbers present in the document. + virtual int GetFirstPageNum(); + virtual int GetPageCount(); + + // Load a specific page of the open document. + virtual FPDF_PAGE LoadPage(int page_number, FPDF_FORMHANDLE form); + + // Convert a loaded page into a bitmap. + virtual FPDF_BITMAP RenderPage(FPDF_PAGE page, FPDF_FORMHANDLE form); + + // Relese the resources obtained from LoadPage(). Further use of |page| + // is prohibited after this call is made. + virtual void UnloadPage(FPDF_PAGE page, FPDF_FORMHANDLE form); + + private: + FPDF_DOCUMENT document_; + FPDF_AVAIL avail_; + FX_DOWNLOADHINTS hints_; + FPDF_FILEACCESS file_access_; + FX_FILEAVAIL file_avail_; + v8::StartupData natives_; + v8::StartupData snapshot_; + TestLoader* loader_; + size_t file_length_; + char* file_contents_; +}; + +#endif // TESTING_EMBEDDER_TEST_H_ + diff --git a/testing/resources/about_blank.pdf b/testing/resources/about_blank.pdf new file mode 100644 index 0000000000..d640582d6a Binary files /dev/null and b/testing/resources/about_blank.pdf differ -- cgit v1.2.3