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