1 // Copyright 2015 PDFium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef TESTING_EMBEDDER_TEST_H_ 6 #define TESTING_EMBEDDER_TEST_H_ 7 8 #include <fstream> 9 #include <map> 10 #include <memory> 11 #include <string> 12 #include <vector> 13 14 #include "build/build_config.h" 15 #include "public/cpp/fpdf_scopers.h" 16 #include "public/fpdf_dataavail.h" 17 #include "public/fpdf_ext.h" 18 #include "public/fpdf_formfill.h" 19 #include "public/fpdf_save.h" 20 #include "public/fpdfview.h" 21 #include "testing/fake_file_access.h" 22 #include "testing/free_deleter.h" 23 #include "testing/gtest/include/gtest/gtest.h" 24 #include "third_party/base/span.h" 25 26 class TestLoader; 27 28 // This class is used to load a PDF document, and then run programatic 29 // API tests against it. 30 class EmbedderTest : public ::testing::Test, 31 public UNSUPPORT_INFO, 32 public IPDF_JSPLATFORM, 33 public FPDF_FORMFILLINFO, 34 public FPDF_FILEWRITE { 35 public: 36 enum class LinearizeOption { kDefaultLinearize, kMustLinearize }; 37 enum class JavaScriptOption { kDisableJavaScript, kEnableJavaScript }; 38 39 class Delegate { 40 public: 41 virtual ~Delegate() = default; 42 43 // Equivalent to UNSUPPORT_INFO::FSDK_UnSupport_Handler(). UnsupportedHandler(int type)44 virtual void UnsupportedHandler(int type) {} 45 46 // Equivalent to IPDF_JSPLATFORM::app_alert(). Alert(FPDF_WIDESTRING message,FPDF_WIDESTRING title,int type,int icon)47 virtual int Alert(FPDF_WIDESTRING message, 48 FPDF_WIDESTRING title, 49 int type, 50 int icon) { 51 return 0; 52 } 53 54 // Equivalent to FPDF_FORMFILLINFO::FFI_SetTimer(). SetTimer(int msecs,TimerCallback fn)55 virtual int SetTimer(int msecs, TimerCallback fn) { return 0; } 56 57 // Equivalent to FPDF_FORMFILLINFO::FFI_KillTimer(). KillTimer(int id)58 virtual void KillTimer(int id) {} 59 60 // Equivalent to FPDF_FORMFILLINFO::FFI_GetPage(). 61 virtual FPDF_PAGE GetPage(FPDF_FORMFILLINFO* info, 62 FPDF_DOCUMENT document, 63 int page_index); 64 65 // Equivalent to FPDF_FORMFILLINFO::FFI_DoURIAction(). DoURIAction(FPDF_BYTESTRING uri)66 virtual void DoURIAction(FPDF_BYTESTRING uri) {} 67 }; 68 69 EmbedderTest(); 70 virtual ~EmbedderTest(); 71 72 void SetUp() override; 73 void TearDown() override; 74 75 #ifdef PDF_ENABLE_V8 76 // Call before SetUp to pass shared isolate, otherwise PDFium creates one. 77 void SetExternalIsolate(void* isolate); 78 #endif // PDF_ENABLE_V8 79 SetDelegate(Delegate * delegate)80 void SetDelegate(Delegate* delegate) { 81 delegate_ = delegate ? delegate : default_delegate_.get(); 82 } 83 document()84 FPDF_DOCUMENT document() const { return document_; } form_handle()85 FPDF_FORMHANDLE form_handle() const { return form_handle_; } 86 87 // Create an empty document, and its form fill environment. Returns true 88 // on success or false on failure. 89 bool CreateEmptyDocument(); 90 91 // Open the document specified by |filename|, and create its form fill 92 // environment, or return false on failure. The |filename| is relative to 93 // the test data directory where we store all the test files. |password| can 94 // be nullptr if the file is not password protected. If |javascript_opts| 95 // is kDisableJavascript, then the document will be given stubs in place 96 // of the real JS engine. 97 virtual bool OpenDocumentWithOptions(const std::string& filename, 98 const char* password, 99 LinearizeOption linearize_option, 100 JavaScriptOption javascript_option); 101 102 // Variants provided for convenience. 103 bool OpenDocument(const std::string& filename); 104 bool OpenDocumentLinearized(const std::string& filename); 105 bool OpenDocumentWithPassword(const std::string& filename, 106 const char* password); 107 bool OpenDocumentWithoutJavaScript(const std::string& filename); 108 109 // Close the document from a previous OpenDocument() call. This happens 110 // automatically at tear-down, and is usually not explicitly required, 111 // unless testing multiple documents or duplicate destruction. 112 void CloseDocument(); 113 114 // Perform JavaScript actions that are to run at document open time. 115 void DoOpenActions(); 116 117 // Determine the page numbers present in the document. 118 int GetFirstPageNum(); 119 int GetPageCount(); 120 121 // Load a specific page of the open document with a given non-negative 122 // |page_number|. On success, fire form events for the page and return a page 123 // handle. On failure, return nullptr. 124 // The caller does not own the returned page handle, but must call 125 // UnloadPage() on it when done. 126 // The caller cannot call this for a |page_number| if it already obtained and 127 // holds the page handle for that page. 128 FPDF_PAGE LoadPage(int page_number); 129 130 // Same as LoadPage(), but does not fire form events. 131 FPDF_PAGE LoadPageNoEvents(int page_number); 132 133 // Fire form unload events and release the resources for a |page| obtained 134 // from LoadPage(). Further use of |page| is prohibited after calling this. 135 void UnloadPage(FPDF_PAGE page); 136 137 // Same as UnloadPage(), but does not fire form events. 138 void UnloadPageNoEvents(FPDF_PAGE page); 139 140 // Apply standard highlighting color/alpha to forms. 141 void SetInitialFormFieldHighlight(FPDF_FORMHANDLE form); 142 143 // RenderLoadedPageWithFlags() with no flags. 144 ScopedFPDFBitmap RenderLoadedPage(FPDF_PAGE page); 145 146 // Convert |page| loaded via LoadPage() into a bitmap with the specified page 147 // rendering |flags|. 148 // 149 // See public/fpdfview.h for a list of page rendering flags. 150 ScopedFPDFBitmap RenderLoadedPageWithFlags(FPDF_PAGE page, int flags); 151 152 // RenderSavedPageWithFlags() with no flags. 153 ScopedFPDFBitmap RenderSavedPage(FPDF_PAGE page); 154 155 // Convert |page| loaded via LoadSavedPage() into a bitmap with the specified 156 // page rendering |flags|. 157 // 158 // See public/fpdfview.h for a list of page rendering flags. 159 ScopedFPDFBitmap RenderSavedPageWithFlags(FPDF_PAGE page, int flags); 160 161 // Convert |page| into a bitmap with the specified page rendering |flags|. 162 // The form handle associated with |page| should be passed in via |handle|. 163 // If |handle| is nullptr, then forms on the page will not be rendered. 164 // 165 // See public/fpdfview.h for a list of page rendering flags. 166 // If none of the above Render methods are appropriate, then use this one. 167 static ScopedFPDFBitmap RenderPageWithFlags(FPDF_PAGE page, 168 FPDF_FORMHANDLE handle, 169 int flags); 170 171 // Simplified form of RenderPageWithFlags() with no handle and no flags. 172 static ScopedFPDFBitmap RenderPage(FPDF_PAGE page); 173 174 #if defined(OS_WIN) 175 // Convert |page| into EMF with the specified page rendering |flags|. 176 static std::vector<uint8_t> RenderPageWithFlagsToEmf(FPDF_PAGE page, 177 int flags); 178 179 // Get the PostScript data from |emf_data|. 180 static std::string GetPostScriptFromEmf(pdfium::span<const uint8_t> emf_data); 181 #endif // defined(OS_WIN) 182 183 // Return bytes for each of the FPDFBitmap_* format types. 184 static int BytesPerPixelForFormat(int format); 185 186 protected: 187 using PageNumberToHandleMap = std::map<int, FPDF_PAGE>; 188 189 bool OpenDocumentHelper(const char* password, 190 LinearizeOption linearize_option, 191 JavaScriptOption javascript_option, 192 FakeFileAccess* network_simulator, 193 FPDF_DOCUMENT* document, 194 FPDF_AVAIL* avail, 195 FPDF_FORMHANDLE* form_handle); 196 197 FPDF_FORMHANDLE SetupFormFillEnvironment(FPDF_DOCUMENT doc, 198 JavaScriptOption javascript_option); 199 200 // Return the hash of only the pixels in |bitmap|. i.e. Excluding the gap, if 201 // any, at the end of a row where the stride is larger than width * bpp. 202 static std::string HashBitmap(FPDF_BITMAP bitmap); 203 204 #ifndef NDEBUG 205 // For debugging purposes. 206 // Write |bitmap| as a PNG to |filename|. 207 static void WriteBitmapToPng(FPDF_BITMAP bitmap, const std::string& filename); 208 #endif 209 210 // Check |bitmap| to make sure it has the right dimensions and content. 211 static void CompareBitmap(FPDF_BITMAP bitmap, 212 int expected_width, 213 int expected_height, 214 const char* expected_md5sum); 215 ClearString()216 void ClearString() { data_string_.clear(); } GetString()217 const std::string& GetString() const { return data_string_; } 218 219 static int GetBlockFromString(void* param, 220 unsigned long pos, 221 unsigned char* buf, 222 unsigned long size); 223 224 // See comments in the respective non-Saved versions of these methods. 225 FPDF_DOCUMENT OpenSavedDocument(); 226 FPDF_DOCUMENT OpenSavedDocumentWithPassword(const char* password); 227 void CloseSavedDocument(); 228 FPDF_PAGE LoadSavedPage(int page_number); 229 void CloseSavedPage(FPDF_PAGE page); 230 231 void VerifySavedRendering(FPDF_PAGE page, 232 int width, 233 int height, 234 const char* md5); 235 void VerifySavedDocument(int width, int height, const char* md5); 236 237 void SetWholeFileAvailable(); 238 239 #ifndef NDEBUG 240 // For debugging purposes. 241 // While open, write any data that gets passed to WriteBlockCallback() to 242 // |filename|. This is typically used to capture data from FPDF_SaveAsCopy() 243 // calls. 244 void OpenPDFFileForWrite(const std::string& filename); 245 void ClosePDFFileForWrite(); 246 #endif 247 248 std::unique_ptr<Delegate> default_delegate_; 249 Delegate* delegate_; 250 251 FPDF_DOCUMENT document_ = nullptr; 252 FPDF_FORMHANDLE form_handle_ = nullptr; 253 FPDF_AVAIL avail_ = nullptr; 254 FPDF_FILEACCESS file_access_; // must outlive |avail_|. 255 std::unique_ptr<FakeFileAccess> fake_file_access_; // must outlive |avail_|. 256 257 void* external_isolate_ = nullptr; 258 std::unique_ptr<TestLoader> loader_; 259 size_t file_length_ = 0; 260 std::unique_ptr<char, pdfium::FreeDeleter> file_contents_; 261 PageNumberToHandleMap page_map_; 262 263 FPDF_DOCUMENT saved_document_ = nullptr; 264 FPDF_FORMHANDLE saved_form_handle_ = nullptr; 265 FPDF_AVAIL saved_avail_ = nullptr; 266 FPDF_FILEACCESS saved_file_access_; // must outlive |saved_avail_|. 267 // must outlive |saved_avail_|. 268 std::unique_ptr<FakeFileAccess> saved_fake_file_access_; 269 PageNumberToHandleMap saved_page_map_; 270 271 private: 272 static void UnsupportedHandlerTrampoline(UNSUPPORT_INFO*, int type); 273 static int AlertTrampoline(IPDF_JSPLATFORM* plaform, 274 FPDF_WIDESTRING message, 275 FPDF_WIDESTRING title, 276 int type, 277 int icon); 278 static int SetTimerTrampoline(FPDF_FORMFILLINFO* info, 279 int msecs, 280 TimerCallback fn); 281 static void KillTimerTrampoline(FPDF_FORMFILLINFO* info, int id); 282 static FPDF_PAGE GetPageTrampoline(FPDF_FORMFILLINFO* info, 283 FPDF_DOCUMENT document, 284 int page_index); 285 static void DoURIActionTrampoline(FPDF_FORMFILLINFO* info, 286 FPDF_BYTESTRING uri); 287 static int WriteBlockCallback(FPDF_FILEWRITE* pFileWrite, 288 const void* data, 289 unsigned long size); 290 291 // Helper method for the methods below. 292 static int GetPageNumberForPage(const PageNumberToHandleMap& page_map, 293 FPDF_PAGE page); 294 // Find |page| inside |page_map_| and return the associated page number, or -1 295 // if |page| cannot be found. 296 int GetPageNumberForLoadedPage(FPDF_PAGE page) const; 297 298 // Same as GetPageNumberForLoadedPage(), but with |saved_page_map_|. 299 int GetPageNumberForSavedPage(FPDF_PAGE page) const; 300 301 void UnloadPageCommon(FPDF_PAGE page, bool do_events); 302 FPDF_PAGE LoadPageCommon(int page_number, bool do_events); 303 304 std::string data_string_; 305 std::string saved_document_file_data_; 306 std::ofstream filestream_; 307 }; 308 309 #endif // TESTING_EMBEDDER_TEST_H_ 310