diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2018-12-10 16:19:40 +0100 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2018-12-10 16:01:50 +0000 |
commit | 51f6c2793adab2d864b3d2b360000ef8db1d3e92 (patch) | |
tree | 835b3b4446b012c75e80177cef9fbe6972cc7dbe /chromium/pdf | |
parent | 6036726eb981b6c4b42047513b9d3f4ac865daac (diff) | |
download | qtwebengine-chromium-51f6c2793adab2d864b3d2b360000ef8db1d3e92.tar.gz |
BASELINE: Update Chromium to 71.0.3578.93
Change-Id: I6a32086c33670e1b033f8b10e6bf1fd4da1d105d
Reviewed-by: Alexandru Croitor <alexandru.croitor@qt.io>
Diffstat (limited to 'chromium/pdf')
36 files changed, 928 insertions, 935 deletions
diff --git a/chromium/pdf/BUILD.gn b/chromium/pdf/BUILD.gn index ee973f481ac..eccebb6f9de 100644 --- a/chromium/pdf/BUILD.gn +++ b/chromium/pdf/BUILD.gn @@ -19,7 +19,19 @@ buildflag_header("buildflags") { if (enable_pdf) { pdf_engine = 0 # 0 PDFium + config("pdf_common_config") { + if (pdf_engine == 0) { + defines = [ "PDFIUM_PRINT_TEXT_WITH_GDI" ] + if (pdf_enable_xfa) { + defines += [ "PDF_ENABLE_XFA" ] + } + + include_dirs = [ "//third_party/pdfium" ] + } + } + jumbo_static_library("pdf") { + configs += [ ":pdf_common_config" ] deps = [ "//base", "//gin", @@ -65,9 +77,6 @@ if (enable_pdf) { "url_loader_wrapper_impl.h", ] - include_dirs = [] - defines = [] - if (pdf_engine == 0) { deps += [ "//pdf/pdfium/fuzzers", @@ -100,17 +109,27 @@ if (enable_pdf) { "pdfium/pdfium_unsupported_features.cc", "pdfium/pdfium_unsupported_features.h", ] + } + } - include_dirs += [ "//third_party/pdfium" ] + source_set("pdf_test_utils") { + testonly = true + sources = [ + "test/test_client.cc", + "test/test_client.h", + "test/test_document_loader.cc", + "test/test_document_loader.h", + ] - defines += [ "PDFIUM_PRINT_TEXT_WITH_GDI" ] - if (pdf_enable_xfa) { - defines += [ "PDF_ENABLE_XFA" ] - } - } + deps = [ + ":pdf", + "//base", + ] } test("pdf_unittests") { + testonly = true + configs += [ ":pdf_common_config" ] sources = [ "chunk_stream_unittest.cc", "document_loader_impl_unittest.cc", @@ -121,6 +140,7 @@ if (enable_pdf) { deps = [ ":pdf", + ":pdf_test_utils", "//base", "//base/test:test_support", "//ppapi/c", @@ -139,8 +159,10 @@ if (enable_pdf) { sources += [ "pdfium/findtext_unittest.cc", "pdfium/pdfium_engine_exports_unittest.cc", + "pdfium/pdfium_print_unittest.cc", + "pdfium/pdfium_test_base.cc", + "pdfium/pdfium_test_base.h", ] - include_dirs = [ "//third_party/pdfium" ] if (v8_use_external_startup_data) { data += [ diff --git a/chromium/pdf/chunk_stream_unittest.cc b/chromium/pdf/chunk_stream_unittest.cc index 5b9ad998606..c6b979e0566 100644 --- a/chromium/pdf/chunk_stream_unittest.cc +++ b/chromium/pdf/chunk_stream_unittest.cc @@ -70,7 +70,7 @@ TEST(ChunkStreamTest, FillGap) { TEST(ChunkStreamTest, Read) { TestChunkStream stream; stream.set_eof_pos(25); - const unsigned char start_value = 33; + constexpr unsigned char start_value = 33; unsigned char value = start_value; auto chunk_0 = CreateChunkData(); for (auto& it : *chunk_0) { diff --git a/chromium/pdf/document_loader_impl.cc b/chromium/pdf/document_loader_impl.cc index f28121815c8..53c9b1f712c 100644 --- a/chromium/pdf/document_loader_impl.cc +++ b/chromium/pdf/document_loader_impl.cc @@ -25,7 +25,7 @@ namespace { // current connection (like playing a cassette tape) and do not send new range // request (like rewind a cassette tape, and continue playing after). // Experimentally chosen value. -const int kChunkCloseDistance = 10; +constexpr int kChunkCloseDistance = 10; // Return true if the HTTP response of |loader| is a successful one and loading // should continue. 4xx error indicate subsequent requests will fail too. diff --git a/chromium/pdf/document_loader_impl_unittest.cc b/chromium/pdf/document_loader_impl_unittest.cc index 0595e049503..9ae3db5df31 100644 --- a/chromium/pdf/document_loader_impl_unittest.cc +++ b/chromium/pdf/document_loader_impl_unittest.cc @@ -232,7 +232,7 @@ class TestClient : public DocumentLoader::Client { partial_loader_data_.CallOpenCallback(0); uint32_t length = partial_loader_data_.byte_range().length(); while (length > 0) { - const uint32_t max_part_len = kDefaultRequestSize; + constexpr uint32_t max_part_len = kDefaultRequestSize; const uint32_t part_len = std::min(length, max_part_len); partial_loader_data_.CallReadCallback(part_len); length -= part_len; @@ -468,7 +468,7 @@ TEST_F(DocumentLoaderImplTest, CompleteWithPartial) { } TEST_F(DocumentLoaderImplTest, PartialRequestLastChunk) { - const uint32_t kLastChunkSize = 300; + constexpr uint32_t kLastChunkSize = 300; TestClient client; client.SetCanUsePartialLoading(); client.full_page_loader_data()->set_content_length(kDefaultRequestSize * 20 + @@ -539,8 +539,8 @@ TEST_F(DocumentLoaderImplTest, ClearPendingRequests) { { EXPECT_TRUE(client.partial_loader_data()->IsWaitOpen()); - const gfx::Range range_requested(15 * kDefaultRequestSize, - 16 * kDefaultRequestSize); + constexpr gfx::Range range_requested(15 * kDefaultRequestSize, + 16 * kDefaultRequestSize); EXPECT_EQ(range_requested.start(), client.partial_loader_data()->open_byte_range().start()); EXPECT_LE(range_requested.end(), @@ -575,8 +575,8 @@ TEST_F(DocumentLoaderImplTest, ClearPendingRequests) { // Loading should be restarted. EXPECT_TRUE(client.partial_loader_data()->IsWaitOpen()); // The first requested chunk should be processed. - const gfx::Range range_requested(35 * kDefaultRequestSize, - 36 * kDefaultRequestSize); + constexpr gfx::Range range_requested(35 * kDefaultRequestSize, + 36 * kDefaultRequestSize); EXPECT_EQ(range_requested.start(), client.partial_loader_data()->open_byte_range().start()); EXPECT_LE(range_requested.end(), @@ -597,8 +597,8 @@ TEST_F(DocumentLoaderImplTest, ClearPendingRequests) { // Loading should be restarted . EXPECT_TRUE(client.partial_loader_data()->IsWaitOpen()); // The first requested chunk should be processed. - const gfx::Range range_requested(70 * kDefaultRequestSize, - 71 * kDefaultRequestSize); + constexpr gfx::Range range_requested(70 * kDefaultRequestSize, + 71 * kDefaultRequestSize); EXPECT_EQ(range_requested.start(), client.partial_loader_data()->open_byte_range().start()); EXPECT_LE(range_requested.end(), @@ -676,8 +676,8 @@ TEST_F(DocumentLoaderImplTest, RequestData) { { EXPECT_TRUE(client.partial_loader_data()->IsWaitOpen()); - const gfx::Range range_requested(13 * kDefaultRequestSize, - 14 * kDefaultRequestSize); + constexpr gfx::Range range_requested(13 * kDefaultRequestSize, + 14 * kDefaultRequestSize); EXPECT_EQ(range_requested.start(), client.partial_loader_data()->open_byte_range().start()); EXPECT_LE(range_requested.end(), @@ -694,8 +694,8 @@ TEST_F(DocumentLoaderImplTest, RequestData) { client.partial_loader_data()->CallReadCallback(kDefaultRequestSize); { EXPECT_TRUE(client.partial_loader_data()->IsWaitOpen()); - const gfx::Range range_requested(26 * kDefaultRequestSize, - 27 * kDefaultRequestSize); + constexpr gfx::Range range_requested(26 * kDefaultRequestSize, + 27 * kDefaultRequestSize); EXPECT_EQ(range_requested.start(), client.partial_loader_data()->open_byte_range().start()); EXPECT_LE(range_requested.end(), @@ -711,8 +711,8 @@ TEST_F(DocumentLoaderImplTest, RequestData) { client.partial_loader_data()->CallReadCallback(kDefaultRequestSize); { EXPECT_TRUE(client.partial_loader_data()->IsWaitOpen()); - const gfx::Range range_requested(39 * kDefaultRequestSize, - 40 * kDefaultRequestSize); + constexpr gfx::Range range_requested(39 * kDefaultRequestSize, + 40 * kDefaultRequestSize); EXPECT_EQ(range_requested.start(), client.partial_loader_data()->open_byte_range().start()); EXPECT_LE(range_requested.end(), @@ -796,8 +796,8 @@ TEST_F(DocumentLoaderImplTest, MergePendingRequests) { // Send initial data from FullPageLoader. client.full_page_loader_data()->CallReadCallback(kDefaultRequestSize); - const gfx::Range range_requested(16 * kDefaultRequestSize, - 18 * kDefaultRequestSize); + constexpr gfx::Range range_requested(16 * kDefaultRequestSize, + 18 * kDefaultRequestSize); EXPECT_EQ(range_requested.start(), client.partial_loader_data()->open_byte_range().start()); EXPECT_LE(range_requested.end(), @@ -1102,7 +1102,7 @@ TEST_F(DocumentLoaderImplTest, IgnoreDataMoreThanExpectedWithPartial) { client.partial_loader_data()->CallOpenCallback(0); uint32_t length = expected_length; while (length > 0) { - const uint32_t max_part_len = kDefaultRequestSize; + constexpr uint32_t max_part_len = kDefaultRequestSize; const uint32_t part_len = std::min(length, max_part_len); client.partial_loader_data()->CallReadCallback(part_len); length -= part_len; @@ -1144,7 +1144,7 @@ TEST_F(DocumentLoaderImplTest, IgnoreDataMoreThanExpectedWithPartialAtFileEnd) { client.partial_loader_data()->CallOpenCallback(0); uint32_t length = client.partial_loader_data()->byte_range().length(); while (length > 0) { - const uint32_t max_part_len = kDefaultRequestSize; + constexpr uint32_t max_part_len = kDefaultRequestSize; const uint32_t part_len = std::min(length, max_part_len); client.partial_loader_data()->CallReadCallback(part_len); length -= part_len; diff --git a/chromium/pdf/draw_utils.cc b/chromium/pdf/draw_utils.cc index 80782521bce..adb2ceb0782 100644 --- a/chromium/pdf/draw_utils.cc +++ b/chromium/pdf/draw_utils.cc @@ -55,7 +55,7 @@ ShadowMatrix::ShadowMatrix(uint32_t depth, double factor, uint32_t background) // pv - is a rounding power factor for smoothing corners. // pv = 2.0 will make corners completely round. - const double pv = 4.0; + constexpr double pv = 4.0; // pow_pv - cache to avoid recalculating pow(x, pv) every time. std::vector<double> pow_pv(depth_, 0.0); diff --git a/chromium/pdf/out_of_process_instance.cc b/chromium/pdf/out_of_process_instance.cc index 0358d15fb45..788082cd637 100644 --- a/chromium/pdf/out_of_process_instance.cc +++ b/chromium/pdf/out_of_process_instance.cc @@ -12,6 +12,7 @@ #include <list> #include <memory> +#include "base/feature_list.h" #include "base/logging.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_split.h" @@ -39,130 +40,142 @@ #include "ppapi/cpp/resource.h" #include "ppapi/cpp/url_request_info.h" #include "ppapi/cpp/var_array.h" +#include "ppapi/cpp/var_array_buffer.h" #include "ppapi/cpp/var_dictionary.h" #include "ui/events/keycodes/keyboard_codes.h" #include "ui/gfx/geometry/point_f.h" +#include "url/gurl.h" namespace chrome_pdf { namespace { -const char kChromePrint[] = "chrome://print/"; -const char kChromeExtension[] = +const base::Feature kSaveEditedPDFFormExperiment{ + "SaveEditedPDFForm", base::FEATURE_DISABLED_BY_DEFAULT}; + +constexpr char kChromePrint[] = "chrome://print/"; +constexpr char kChromeExtension[] = "chrome-extension://mhjfbmdgcfjbbpaeojofohoefgiehjai"; // Constants used in handling postMessage() messages. -const char kType[] = "type"; -const char kJSId[] = "id"; +constexpr char kType[] = "type"; +constexpr char kJSId[] = "id"; // Beep messge arguments. (Plugin -> Page). -const char kJSBeepType[] = "beep"; +constexpr char kJSBeepType[] = "beep"; // Viewport message arguments. (Page -> Plugin). -const char kJSViewportType[] = "viewport"; -const char kJSUserInitiated[] = "userInitiated"; -const char kJSXOffset[] = "xOffset"; -const char kJSYOffset[] = "yOffset"; -const char kJSZoom[] = "zoom"; -const char kJSPinchPhase[] = "pinchPhase"; +constexpr char kJSViewportType[] = "viewport"; +constexpr char kJSUserInitiated[] = "userInitiated"; +constexpr char kJSXOffset[] = "xOffset"; +constexpr char kJSYOffset[] = "yOffset"; +constexpr char kJSZoom[] = "zoom"; +constexpr char kJSPinchPhase[] = "pinchPhase"; // kJSPinchX and kJSPinchY represent the center of the pinch gesture. -const char kJSPinchX[] = "pinchX"; -const char kJSPinchY[] = "pinchY"; +constexpr char kJSPinchX[] = "pinchX"; +constexpr char kJSPinchY[] = "pinchY"; // kJSPinchVector represents the amount of panning caused by the pinch gesture. -const char kJSPinchVectorX[] = "pinchVectorX"; -const char kJSPinchVectorY[] = "pinchVectorY"; +constexpr char kJSPinchVectorX[] = "pinchVectorX"; +constexpr char kJSPinchVectorY[] = "pinchVectorY"; // Stop scrolling message (Page -> Plugin) -const char kJSStopScrollingType[] = "stopScrolling"; +constexpr char kJSStopScrollingType[] = "stopScrolling"; // Document dimension arguments (Plugin -> Page). -const char kJSDocumentDimensionsType[] = "documentDimensions"; -const char kJSDocumentWidth[] = "width"; -const char kJSDocumentHeight[] = "height"; -const char kJSPageDimensions[] = "pageDimensions"; -const char kJSPageX[] = "x"; -const char kJSPageY[] = "y"; -const char kJSPageWidth[] = "width"; -const char kJSPageHeight[] = "height"; +constexpr char kJSDocumentDimensionsType[] = "documentDimensions"; +constexpr char kJSDocumentWidth[] = "width"; +constexpr char kJSDocumentHeight[] = "height"; +constexpr char kJSPageDimensions[] = "pageDimensions"; +constexpr char kJSPageX[] = "x"; +constexpr char kJSPageY[] = "y"; +constexpr char kJSPageWidth[] = "width"; +constexpr char kJSPageHeight[] = "height"; // Document load progress arguments (Plugin -> Page) -const char kJSLoadProgressType[] = "loadProgress"; -const char kJSProgressPercentage[] = "progress"; +constexpr char kJSLoadProgressType[] = "loadProgress"; +constexpr char kJSProgressPercentage[] = "progress"; // Document print preview loaded (Plugin -> Page) -const char kJSPreviewLoadedType[] = "printPreviewLoaded"; +constexpr char kJSPreviewLoadedType[] = "printPreviewLoaded"; // Metadata -const char kJSMetadataType[] = "metadata"; -const char kJSBookmarks[] = "bookmarks"; -const char kJSTitle[] = "title"; +constexpr char kJSMetadataType[] = "metadata"; +constexpr char kJSBookmarks[] = "bookmarks"; +constexpr char kJSTitle[] = "title"; // Get password (Plugin -> Page) -const char kJSGetPasswordType[] = "getPassword"; +constexpr char kJSGetPasswordType[] = "getPassword"; // Get password complete arguments (Page -> Plugin) -const char kJSGetPasswordCompleteType[] = "getPasswordComplete"; -const char kJSPassword[] = "password"; +constexpr char kJSGetPasswordCompleteType[] = "getPasswordComplete"; +constexpr char kJSPassword[] = "password"; // Print (Page -> Plugin) -const char kJSPrintType[] = "print"; +constexpr char kJSPrintType[] = "print"; // Save (Page -> Plugin) -const char kJSSaveType[] = "save"; +constexpr char kJSSaveType[] = "save"; +constexpr char kJSToken[] = "token"; +// Save Data (Plugin -> Page) +constexpr char kJSSaveDataType[] = "saveData"; +constexpr char kJSFileName[] = "fileName"; +constexpr char kJSDataToSave[] = "dataToSave"; +// Consume save token (Plugin -> Page) +constexpr char kJSConsumeSaveTokenType[] = "consumeSaveToken"; // Go to page (Plugin -> Page) -const char kJSGoToPageType[] = "goToPage"; -const char kJSPageNumber[] = "page"; +constexpr char kJSGoToPageType[] = "goToPage"; +constexpr char kJSPageNumber[] = "page"; // Reset print preview mode (Page -> Plugin) -const char kJSResetPrintPreviewModeType[] = "resetPrintPreviewMode"; -const char kJSPrintPreviewUrl[] = "url"; -const char kJSPrintPreviewGrayscale[] = "grayscale"; -const char kJSPrintPreviewPageCount[] = "pageCount"; +constexpr char kJSResetPrintPreviewModeType[] = "resetPrintPreviewMode"; +constexpr char kJSPrintPreviewUrl[] = "url"; +constexpr char kJSPrintPreviewGrayscale[] = "grayscale"; +constexpr char kJSPrintPreviewPageCount[] = "pageCount"; // Load preview page (Page -> Plugin) -const char kJSLoadPreviewPageType[] = "loadPreviewPage"; -const char kJSPreviewPageUrl[] = "url"; -const char kJSPreviewPageIndex[] = "index"; +constexpr char kJSLoadPreviewPageType[] = "loadPreviewPage"; +constexpr char kJSPreviewPageUrl[] = "url"; +constexpr char kJSPreviewPageIndex[] = "index"; // Set scroll position (Plugin -> Page) -const char kJSSetScrollPositionType[] = "setScrollPosition"; -const char kJSPositionX[] = "x"; -const char kJSPositionY[] = "y"; +constexpr char kJSSetScrollPositionType[] = "setScrollPosition"; +constexpr char kJSPositionX[] = "x"; +constexpr char kJSPositionY[] = "y"; // Scroll by (Plugin -> Page) -const char kJSScrollByType[] = "scrollBy"; +constexpr char kJSScrollByType[] = "scrollBy"; // Cancel the stream URL request (Plugin -> Page) -const char kJSCancelStreamUrlType[] = "cancelStreamUrl"; +constexpr char kJSCancelStreamUrlType[] = "cancelStreamUrl"; // Navigate to the given URL (Plugin -> Page) -const char kJSNavigateType[] = "navigate"; -const char kJSNavigateUrl[] = "url"; -const char kJSNavigateWindowOpenDisposition[] = "disposition"; +constexpr char kJSNavigateType[] = "navigate"; +constexpr char kJSNavigateUrl[] = "url"; +constexpr char kJSNavigateWindowOpenDisposition[] = "disposition"; // Open the email editor with the given parameters (Plugin -> Page) -const char kJSEmailType[] = "email"; -const char kJSEmailTo[] = "to"; -const char kJSEmailCc[] = "cc"; -const char kJSEmailBcc[] = "bcc"; -const char kJSEmailSubject[] = "subject"; -const char kJSEmailBody[] = "body"; +constexpr char kJSEmailType[] = "email"; +constexpr char kJSEmailTo[] = "to"; +constexpr char kJSEmailCc[] = "cc"; +constexpr char kJSEmailBcc[] = "bcc"; +constexpr char kJSEmailSubject[] = "subject"; +constexpr char kJSEmailBody[] = "body"; // Rotation (Page -> Plugin) -const char kJSRotateClockwiseType[] = "rotateClockwise"; -const char kJSRotateCounterclockwiseType[] = "rotateCounterclockwise"; +constexpr char kJSRotateClockwiseType[] = "rotateClockwise"; +constexpr char kJSRotateCounterclockwiseType[] = "rotateCounterclockwise"; // Select all text in the document (Page -> Plugin) -const char kJSSelectAllType[] = "selectAll"; +constexpr char kJSSelectAllType[] = "selectAll"; // Get the selected text in the document (Page -> Plugin) -const char kJSGetSelectedTextType[] = "getSelectedText"; +constexpr char kJSGetSelectedTextType[] = "getSelectedText"; // Reply with selected text (Plugin -> Page) -const char kJSGetSelectedTextReplyType[] = "getSelectedTextReply"; -const char kJSSelectedText[] = "selectedText"; +constexpr char kJSGetSelectedTextReplyType[] = "getSelectedTextReply"; +constexpr char kJSSelectedText[] = "selectedText"; // Get the named destination with the given name (Page -> Plugin) -const char kJSGetNamedDestinationType[] = "getNamedDestination"; -const char kJSGetNamedDestination[] = "namedDestination"; +constexpr char kJSGetNamedDestinationType[] = "getNamedDestination"; +constexpr char kJSGetNamedDestination[] = "namedDestination"; // Reply with the page number of the named destination (Plugin -> Page) -const char kJSGetNamedDestinationReplyType[] = "getNamedDestinationReply"; -const char kJSNamedDestinationPageNumber[] = "pageNumber"; +constexpr char kJSGetNamedDestinationReplyType[] = "getNamedDestinationReply"; +constexpr char kJSNamedDestinationPageNumber[] = "pageNumber"; -const char kJSTransformPagePointType[] = "transformPagePoint"; -const char kJSTransformPagePointReplyType[] = "transformPagePointReply"; +constexpr char kJSTransformPagePointType[] = "transformPagePoint"; +constexpr char kJSTransformPagePointReplyType[] = "transformPagePointReply"; // Selecting text in document (Plugin -> Page) -const char kJSSetIsSelectingType[] = "setIsSelecting"; -const char kJSIsSelecting[] = "isSelecting"; - -// Notify when the document was changed and edit mode is toggled. -const char kJSSetIsEditModeType[] = "setIsEditMode"; -const char kJSIsEditMode[] = "isEditMode"; +constexpr char kJSSetIsSelectingType[] = "setIsSelecting"; +constexpr char kJSIsSelecting[] = "isSelecting"; // Notify when a form field is focused (Plugin -> Page) -const char kJSFieldFocusType[] = "formFocusChange"; -const char kJSFieldFocus[] = "focused"; +constexpr char kJSFieldFocusType[] = "formFocusChange"; +constexpr char kJSFieldFocus[] = "focused"; + +constexpr int kFindResultCooldownMs = 100; -const int kFindResultCooldownMs = 100; +// Do not save forms with over 100 MB. This cap should be kept in sync with and +// is also enforced in chrome/browser/resources/pdf/pdf_viewer.js. +constexpr size_t kMaximumSavedFileSize = 100u * 1000u * 1000u; // Same value as printing::COMPLETE_PREVIEW_DOCUMENT_INDEX. constexpr int kCompletePDFIndex = -1; @@ -171,11 +184,11 @@ constexpr int kInvalidPDFIndex = -2; // A delay to wait between each accessibility page to keep the system // responsive. -const int kAccessibilityPageDelayMs = 100; +constexpr int kAccessibilityPageDelayMs = 100; -const double kMinZoom = 0.01; +constexpr double kMinZoom = 0.01; -const char kPPPPdfInterface[] = PPP_PDF_INTERFACE_1; +constexpr char kPPPPdfInterface[] = PPP_PDF_INTERFACE_1; // Used for UMA. Do not delete entries, and keep in sync with histograms.xml. enum PDFFeatures { @@ -187,7 +200,7 @@ enum PDFFeatures { // Used for UMA. Do not delete entries, and keep in sync with histograms.xml // and pdfium/public/fpdf_annot.h. -const int kAnnotationTypesCount = 28; +constexpr int kAnnotationTypesCount = 28; PP_Var GetLinkAtPosition(PP_Instance instance, PP_Point point) { pp::Var var; @@ -651,9 +664,8 @@ void OutOfProcessInstance::HandleMessage(const pp::Var& message) { } } else if (type == kJSPrintType) { Print(); - } else if (type == kJSSaveType) { - engine_->KillFormFocus(); - pp::PDF::SaveAs(this); + } else if (type == kJSSaveType && dict.Get(pp::Var(kJSToken)).is_string()) { + Save(dict.Get(pp::Var(kJSToken)).AsString()); } else if (type == kJSRotateClockwiseType) { RotateClockwise(); } else if (type == kJSRotateCounterclockwiseType) { @@ -1461,6 +1473,44 @@ void OutOfProcessInstance::GetDocumentPassword( PostMessage(message); } +void OutOfProcessInstance::Save(const std::string& token) { + engine_->KillFormFocus(); + + if (!base::FeatureList::IsEnabled(kSaveEditedPDFFormExperiment) || + !edit_mode_) { + ConsumeSaveToken(token); + pp::PDF::SaveAs(this); + return; + } + + GURL url(url_); + std::string file_name = url.ExtractFileName(); + file_name = net::UnescapeURLComponent(file_name, net::UnescapeRule::SPACES); + std::vector<uint8_t> data = engine_->GetSaveData(); + + if (data.size() == 0u || data.size() > kMaximumSavedFileSize) { + // TODO(thestig): Add feedback to the user that a failure occurred. + ConsumeSaveToken(token); + return; + } + + pp::VarDictionary message; + message.Set(kType, kJSSaveDataType); + message.Set(kJSToken, pp::Var(token)); + message.Set(kJSFileName, pp::Var(file_name)); + pp::VarArrayBuffer buffer(data.size()); + std::copy(data.begin(), data.end(), reinterpret_cast<char*>(buffer.Map())); + message.Set(kJSDataToSave, buffer); + PostMessage(message); +} + +void OutOfProcessInstance::ConsumeSaveToken(const std::string& token) { + pp::VarDictionary message; + message.Set(kType, kJSConsumeSaveTokenType); + message.Set(kJSToken, pp::Var(token)); + PostMessage(message); +} + void OutOfProcessInstance::Beep() { pp::VarDictionary message; message.Set(pp::Var(kType), pp::Var(kJSBeepType)); @@ -1652,7 +1702,7 @@ void OutOfProcessInstance::DocumentLoadComplete( } pp::PDF::SetContentRestriction(this, content_restrictions); - static const int32_t kMaxFileSizeInKB = 12 * 1024 * 1024; + static constexpr int32_t kMaxFileSizeInKB = 12 * 1024 * 1024; HistogramCustomCounts("PDF.FileSizeInKB", file_size / 1024, 0, kMaxFileSizeInKB, 50); HistogramCustomCounts("PDF.PageCount", document_features.page_count, 1, @@ -1898,10 +1948,7 @@ void OutOfProcessInstance::IsSelectingChanged(bool is_selecting) { } void OutOfProcessInstance::IsEditModeChanged(bool is_edit_mode) { - pp::VarDictionary message; - message.Set(kType, kJSSetIsEditModeType); - message.Set(kJSIsEditMode, pp::Var(is_edit_mode)); - PostMessage(message); + edit_mode_ = is_edit_mode; } float OutOfProcessInstance::GetToolbarHeightInScreenCoords() { diff --git a/chromium/pdf/out_of_process_instance.h b/chromium/pdf/out_of_process_instance.h index 18ce4321f15..2c91f54f1d1 100644 --- a/chromium/pdf/out_of_process_instance.h +++ b/chromium/pdf/out_of_process_instance.h @@ -186,6 +186,9 @@ class OutOfProcessInstance : public pp::Instance, // frame's origin. pp::URLLoader CreateURLLoaderInternal(); + void Save(const std::string& token); + void ConsumeSaveToken(const std::string& token); + void FormDidOpen(int32_t result); void UserMetricsRecordAction(const std::string& action); @@ -427,6 +430,8 @@ class OutOfProcessInstance : public pp::Instance, // Annotation types that were already counted for this document. std::set<int> annotation_types_counted_; + bool edit_mode_ = false; + // The current state of accessibility: either off, enabled but waiting // for the document to load, or fully loaded. enum AccessibilityState { diff --git a/chromium/pdf/paint_manager.cc b/chromium/pdf/paint_manager.cc index fdccaef481b..e83805e0e0a 100644 --- a/chromium/pdf/paint_manager.cc +++ b/chromium/pdf/paint_manager.cc @@ -55,7 +55,7 @@ pp::Size PaintManager::GetNewContextSize(const pp::Size& current_context_size, const pp::Size& plugin_size) { // The amount of additional space in pixels to allocate to the right/bottom of // the context. - const int kBufferSize = 50; + constexpr int kBufferSize = 50; // Default to returning the same size. pp::Size result = current_context_size; diff --git a/chromium/pdf/pdf.cc b/chromium/pdf/pdf.cc index bfa6a4b8ad0..c45791a92b7 100644 --- a/chromium/pdf/pdf.cc +++ b/chromium/pdf/pdf.cc @@ -139,27 +139,29 @@ bool RenderPDFPageToBitmap(base::span<const uint8_t> pdf_buffer, std::vector<uint8_t> ConvertPdfPagesToNupPdf( std::vector<base::span<const uint8_t>> input_buffers, size_t pages_per_sheet, - const gfx::Size& page_size) { + const gfx::Size& page_size, + const gfx::Rect& printable_area) { ScopedSdkInitializer scoped_sdk_initializer; if (!scoped_sdk_initializer.Init()) return std::vector<uint8_t>(); PDFEngineExports* engine_exports = PDFEngineExports::Get(); - return engine_exports->ConvertPdfPagesToNupPdf(std::move(input_buffers), - pages_per_sheet, page_size); + return engine_exports->ConvertPdfPagesToNupPdf( + std::move(input_buffers), pages_per_sheet, page_size, printable_area); } std::vector<uint8_t> ConvertPdfDocumentToNupPdf( base::span<const uint8_t> input_buffer, size_t pages_per_sheet, - const gfx::Size& page_size) { + const gfx::Size& page_size, + const gfx::Rect& printable_area) { ScopedSdkInitializer scoped_sdk_initializer; if (!scoped_sdk_initializer.Init()) return std::vector<uint8_t>(); PDFEngineExports* engine_exports = PDFEngineExports::Get(); - return engine_exports->ConvertPdfDocumentToNupPdf(input_buffer, - pages_per_sheet, page_size); + return engine_exports->ConvertPdfDocumentToNupPdf( + input_buffer, pages_per_sheet, page_size, printable_area); } } // namespace chrome_pdf diff --git a/chromium/pdf/pdf.h b/chromium/pdf/pdf.h index 4617943b003..f17b7ea9839 100644 --- a/chromium/pdf/pdf.h +++ b/chromium/pdf/pdf.h @@ -21,6 +21,7 @@ typedef void (*PDFEnsureTypefaceCharactersAccessible)(const LOGFONT* font, #endif namespace gfx { +class Rect; class Size; } @@ -132,6 +133,8 @@ bool RenderPDFPageToBitmap(base::span<const uint8_t> pdf_buffer, // document is used. // |pages_per_sheet| is the number of pages to put on one sheet. // |page_size| is the output page size, measured in PDF "user space" units. +// |printable_area| is the output page printable area, measured in PDF +// "user space" units. Should be smaller than |page_size|. // // |page_size| is the print media size. The page size of the output N-up PDF is // determined by the |pages_per_sheet|, the orientation of the PDF pages @@ -145,13 +148,16 @@ bool RenderPDFPageToBitmap(base::span<const uint8_t> pdf_buffer, std::vector<uint8_t> ConvertPdfPagesToNupPdf( std::vector<base::span<const uint8_t>> input_buffers, size_t pages_per_sheet, - const gfx::Size& page_size); + const gfx::Size& page_size, + const gfx::Rect& printable_area); // Convert a PDF document to a N-up PDF document. // |input_buffer| is the buffer that contains the entire PDF document to be // converted to a N-up PDF document. // |pages_per_sheet| is the number of pages to put on one sheet. // |page_size| is the output page size, measured in PDF "user space" units. +// |printable_area| is the output page printable area, measured in PDF +// "user space" units. Should be smaller than |page_size|. // // Refer to the description of ConvertPdfPagesToNupPdf to understand how the // output page size will be calculated. @@ -159,7 +165,8 @@ std::vector<uint8_t> ConvertPdfPagesToNupPdf( std::vector<uint8_t> ConvertPdfDocumentToNupPdf( base::span<const uint8_t> input_buffer, size_t pages_per_sheet, - const gfx::Size& page_size); + const gfx::Size& page_size, + const gfx::Rect& printable_area); } // namespace chrome_pdf diff --git a/chromium/pdf/pdf_engine.h b/chromium/pdf/pdf_engine.h index 521337eb06a..047f24611e1 100644 --- a/chromium/pdf/pdf_engine.h +++ b/chromium/pdf/pdf_engine.h @@ -42,6 +42,7 @@ typedef void (*PDFEnsureTypefaceCharactersAccessible)(const LOGFONT* font, struct PP_PdfPrintSettings_Dev; namespace gfx { +class Rect; class Size; } @@ -401,6 +402,7 @@ class PDFEngine { virtual void AppendPage(PDFEngine* engine, int index) = 0; virtual std::string GetMetadata(const std::string& key) = 0; + virtual std::vector<uint8_t> GetSaveData() = 0; virtual void SetCaretPosition(const pp::Point& position) = 0; virtual void MoveRangeSelectionExtent(const pp::Point& extent) = 0; @@ -470,13 +472,15 @@ class PDFEngineExports { virtual std::vector<uint8_t> ConvertPdfPagesToNupPdf( std::vector<base::span<const uint8_t>> input_buffers, size_t pages_per_sheet, - const gfx::Size& page_size) = 0; + const gfx::Size& page_size, + const gfx::Rect& printable_area) = 0; // See the definition of ConvertPdfDocumentToNupPdf in pdf.cc for details. virtual std::vector<uint8_t> ConvertPdfDocumentToNupPdf( base::span<const uint8_t> input_buffer, size_t pages_per_sheet, - const gfx::Size& page_size) = 0; + const gfx::Size& page_size, + const gfx::Rect& printable_area) = 0; virtual bool GetPDFDocInfo(base::span<const uint8_t> pdf_buffer, int* page_count, diff --git a/chromium/pdf/pdf_transform.cc b/chromium/pdf/pdf_transform.cc index 28a69de503f..0acb36c44bc 100644 --- a/chromium/pdf/pdf_transform.cc +++ b/chromium/pdf/pdf_transform.cc @@ -42,9 +42,9 @@ double CalculateScaleFactor(const gfx::Rect& content_rect, } void SetDefaultClipBox(bool rotated, PdfRectangle* clip_box) { - const int kDpi = 72; - const float kPaperWidth = 8.5 * kDpi; - const float kPaperHeight = 11 * kDpi; + constexpr int kDpi = 72; + constexpr float kPaperWidth = 8.5 * kDpi; + constexpr float kPaperHeight = 11 * kDpi; clip_box->left = 0; clip_box->bottom = 0; clip_box->right = rotated ? kPaperHeight : kPaperWidth; diff --git a/chromium/pdf/pdf_transform_unittest.cc b/chromium/pdf/pdf_transform_unittest.cc index e52b02a8665..faf424e8c9b 100644 --- a/chromium/pdf/pdf_transform_unittest.cc +++ b/chromium/pdf/pdf_transform_unittest.cc @@ -12,10 +12,10 @@ namespace chrome_pdf { namespace { -const float kDefaultWidth = 8.5 * printing::kPointsPerInch; -const float kDefaultHeight = 11.0 * printing::kPointsPerInch; -const float kDefaultRatio = kDefaultWidth / kDefaultHeight; -const double kTolerance = 0.0001; +constexpr float kDefaultWidth = 8.5 * printing::kPointsPerInch; +constexpr float kDefaultHeight = 11.0 * printing::kPointsPerInch; +constexpr float kDefaultRatio = kDefaultWidth / kDefaultHeight; +constexpr double kTolerance = 0.0001; void ExpectDefaultPortraitBox(const PdfRectangle& box) { EXPECT_FLOAT_EQ(0, box.left); @@ -130,7 +130,7 @@ TEST(PdfTransformTest, CalculateMediaBoxAndCropBox) { ExpectDefaultLandscapeBox(crop_box); // Assume crop box is missing. - const PdfRectangle expected_box = {0, 0, 42, 420}; + constexpr PdfRectangle expected_box = {0, 0, 42, 420}; media_box = expected_box; InitializeBoxToInvalidValues(&crop_box); CalculateMediaBoxAndCropBox(false, true, false, &media_box, &crop_box); @@ -188,7 +188,7 @@ TEST(PdfTransformTest, CalculateClipBoxBoundary) { } TEST(PdfTransformTest, CalculateScaledClipBoxOffset) { - const gfx::Rect rect(kDefaultWidth, kDefaultHeight); + constexpr gfx::Rect rect(kDefaultWidth, kDefaultHeight); PdfRectangle clip_box; double offset_x; double offset_y; @@ -210,7 +210,7 @@ TEST(PdfTransformTest, CalculateScaledClipBoxOffset) { TEST(PdfTransformTest, CalculateNonScaledClipBoxOffset) { int page_width = kDefaultWidth; int page_height = kDefaultHeight; - const gfx::Rect rect(kDefaultWidth, kDefaultHeight); + constexpr gfx::Rect rect(kDefaultWidth, kDefaultHeight); PdfRectangle clip_box; double offset_x; double offset_y; @@ -280,12 +280,12 @@ TEST(PdfTransformTest, CalculateNonScaledClipBoxOffset) { TEST(PdfTransformTest, ReversedMediaBox) { int page_width = kDefaultWidth; int page_height = kDefaultHeight; - const gfx::Rect rect(kDefaultWidth, kDefaultHeight); + constexpr gfx::Rect rect(kDefaultWidth, kDefaultHeight); PdfRectangle clip_box; double offset_x; double offset_y; - const PdfRectangle expected_media_box_b491160 = {0, -792, 612, 0}; + constexpr PdfRectangle expected_media_box_b491160 = {0, -792, 612, 0}; PdfRectangle media_box_b491160 = {0, 0, 612, -792}; CalculateMediaBoxAndCropBox(false, true, false, &media_box_b491160, &clip_box); diff --git a/chromium/pdf/pdfium/DEPS b/chromium/pdf/pdfium/DEPS index f157a81c75d..e8058f09b8a 100644 --- a/chromium/pdf/pdfium/DEPS +++ b/chromium/pdf/pdfium/DEPS @@ -3,6 +3,7 @@ include_rules = [ "+gin/public", "+gin/v8_initializer.h", "+printing/nup_parameters.h", + "+printing/page_setup.h", "+third_party/pdfium/public", "+ui/gfx/codec/jpeg_codec.h", ] diff --git a/chromium/pdf/pdfium/findtext_unittest.cc b/chromium/pdf/pdfium/findtext_unittest.cc index c077b748515..895fc39d66a 100644 --- a/chromium/pdf/pdfium/findtext_unittest.cc +++ b/chromium/pdf/pdfium/findtext_unittest.cc @@ -2,14 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "base/files/file_util.h" #include "base/optional.h" -#include "base/path_service.h" -#include "pdf/document_loader.h" #include "pdf/pdfium/pdfium_engine.h" -#include "pdf/url_loader_wrapper.h" +#include "pdf/pdfium/pdfium_test_base.h" +#include "pdf/test/test_client.h" #include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" using testing::InSequence; using testing::_; @@ -18,79 +15,15 @@ namespace chrome_pdf { namespace { -class TestDocumentLoader : public DocumentLoader { +class FindTextTestClient : public TestClient { public: - explicit TestDocumentLoader(Client* client) : client_(client) { - base::FilePath pdf_path; - CHECK(base::PathService::Get(base::DIR_SOURCE_ROOT, &pdf_path)); - pdf_path = pdf_path.Append(FILE_PATH_LITERAL("pdf")) - .Append(FILE_PATH_LITERAL("test")) - .Append(FILE_PATH_LITERAL("data")) - .Append(FILE_PATH_LITERAL("hello_world2.pdf")); - CHECK(base::ReadFileToString(pdf_path, &pdf_data_)); - } - ~TestDocumentLoader() override = default; - - // DocumentLoader: - bool Init(std::unique_ptr<URLLoaderWrapper> loader, - const std::string& url) override { - NOTREACHED(); - return false; - } - - bool GetBlock(uint32_t position, uint32_t size, void* buf) const override { - if (!IsDataAvailable(position, size)) - return false; - - memcpy(buf, pdf_data_.data() + position, size); - return true; - } - - bool IsDataAvailable(uint32_t position, uint32_t size) const override { - return position < pdf_data_.size() && size <= pdf_data_.size() && - position + size <= pdf_data_.size(); - } - - void RequestData(uint32_t position, uint32_t size) override { - client_->OnDocumentComplete(); - } - - bool IsDocumentComplete() const override { return true; } - - uint32_t GetDocumentSize() const override { return pdf_data_.size(); } - - uint32_t BytesReceived() const override { return pdf_data_.size(); } - - private: - Client* const client_; - std::string pdf_data_; -}; - -std::unique_ptr<DocumentLoader> CreateTestDocumentLoader( - DocumentLoader::Client* client) { - return std::make_unique<TestDocumentLoader>(client); -} - -class TestClient : public PDFEngine::Client { - public: - TestClient() = default; - ~TestClient() override = default; + FindTextTestClient() = default; + ~FindTextTestClient() override = default; // PDFEngine::Client: MOCK_METHOD2(NotifyNumberOfFindResultsChanged, void(int, bool)); MOCK_METHOD1(NotifySelectedFindResultChanged, void((int))); - bool Confirm(const std::string& message) override { return false; } - - std::string Prompt(const std::string& question, - const std::string& default_answer) override { - return std::string(); - } - - std::string GetURL() override { return std::string(); } - - pp::URLLoader CreateURLLoader() override { return pp::URLLoader(); } - std::vector<SearchStringResult> SearchString(const base::char16* string, const base::char16* term, bool case_sensitive) override { @@ -115,54 +48,19 @@ class TestClient : public PDFEngine::Client { return results; } - pp::Instance* GetPluginInstance() override { return nullptr; } - - bool IsPrintPreview() override { return false; } - - uint32_t GetBackgroundColor() override { return 0; } - - float GetToolbarHeightInScreenCoords() override { return 0; } - private: - DISALLOW_COPY_AND_ASSIGN(TestClient); + DISALLOW_COPY_AND_ASSIGN(FindTextTestClient); }; } // namespace -class FindTextTest : public testing::Test { - public: - FindTextTest() = default; - ~FindTextTest() override = default; - - protected: - void SetUp() override { - InitializePDFium(); - PDFiumEngine::SetCreateDocumentLoaderFunctionForTesting( - &CreateTestDocumentLoader); - } - void TearDown() override { - PDFiumEngine::SetCreateDocumentLoaderFunctionForTesting(nullptr); - FPDF_DestroyLibrary(); - } - - void InitializePDFium() { - FPDF_LIBRARY_CONFIG config; - config.version = 2; - config.m_pUserFontPaths = nullptr; - config.m_pIsolate = nullptr; - config.m_v8EmbedderSlot = 0; - FPDF_InitLibraryWithConfig(&config); - } - - DISALLOW_COPY_AND_ASSIGN(FindTextTest); -}; +using FindTextTest = PDFiumTestBase; TEST_F(FindTextTest, FindText) { - pp::URLLoader dummy_loader; - TestClient client; - PDFiumEngine engine(&client, true); - ASSERT_TRUE(engine.New("https://chromium.org/dummy.pdf", "")); - ASSERT_TRUE(engine.HandleDocumentLoad(dummy_loader)); + FindTextTestClient client; + std::unique_ptr<PDFiumEngine> engine = + InitializeEngine(&client, FILE_PATH_LITERAL("hello_world2.pdf")); + ASSERT_TRUE(engine); { InSequence sequence; @@ -174,7 +72,43 @@ TEST_F(FindTextTest, FindText) { EXPECT_CALL(client, NotifyNumberOfFindResultsChanged(10, true)); } - engine.StartFind("o", /*case_sensitive=*/true); + engine->StartFind("o", /*case_sensitive=*/true); +} + +TEST_F(FindTextTest, FindHyphenatedText) { + FindTextTestClient client; + std::unique_ptr<PDFiumEngine> engine = + InitializeEngine(&client, FILE_PATH_LITERAL("spanner.pdf")); + ASSERT_TRUE(engine); + + { + InSequence sequence; + + EXPECT_CALL(client, NotifyNumberOfFindResultsChanged(1, false)); + EXPECT_CALL(client, NotifySelectedFindResultChanged(0)); + for (int i = 1; i < 6; ++i) + EXPECT_CALL(client, NotifyNumberOfFindResultsChanged(i + 1, false)); + EXPECT_CALL(client, NotifyNumberOfFindResultsChanged(6, true)); + } + + engine->StartFind("application", /*case_sensitive=*/true); +} + +TEST_F(FindTextTest, FindLineBreakText) { + FindTextTestClient client; + std::unique_ptr<PDFiumEngine> engine = + InitializeEngine(&client, FILE_PATH_LITERAL("spanner.pdf")); + ASSERT_TRUE(engine); + + { + InSequence sequence; + + EXPECT_CALL(client, NotifyNumberOfFindResultsChanged(1, false)); + EXPECT_CALL(client, NotifySelectedFindResultChanged(0)); + EXPECT_CALL(client, NotifyNumberOfFindResultsChanged(1, true)); + } + + engine->StartFind("is the first system", /*case_sensitive=*/true); } } // namespace chrome_pdf diff --git a/chromium/pdf/pdfium/fuzzers/BUILD.gn b/chromium/pdf/pdfium/fuzzers/BUILD.gn index ffac41d48fc..124139ea78b 100644 --- a/chromium/pdf/pdfium/fuzzers/BUILD.gn +++ b/chromium/pdf/pdfium/fuzzers/BUILD.gn @@ -59,23 +59,16 @@ group("pdf_fuzzers") { } fuzzer_test("pdfium_fuzzer") { - sources = [ - "pdfium_fuzzer.cc", - "pdfium_fuzzer_helper.cc", - "pdfium_fuzzer_helper.h", - ] + sources = [] deps = [ - "//third_party/pdfium", - "//third_party/pdfium:test_support", - "//v8", - "//v8:v8_libplatform", - ] - additional_configs = [ - "//third_party/pdfium:pdfium_core_config", - "//v8:external_startup_data", + "//third_party/pdfium/testing/fuzzers:pdfium_fuzzer_src", ] dict = "dicts/pdf.dict" seed_corpus = "//third_party/pdfium/testing/resources" + deps += [ + "//third_party/pdfium", + "//third_party/pdfium:test_support", + ] } fuzzer_test("pdf_cmap_fuzzer") { @@ -271,20 +264,9 @@ if (pdf_enable_xfa) { } fuzzer_test("pdfium_xfa_fuzzer") { - sources = [ - "pdfium_fuzzer_helper.cc", - "pdfium_fuzzer_helper.h", - "pdfium_xfa_fuzzer.cc", - ] + sources = [] deps = [ - "//third_party/pdfium", - "//third_party/pdfium:test_support", - "//v8", - "//v8:v8_libplatform", - ] - additional_configs = [ - "//third_party/pdfium:pdfium_core_config", - "//v8:external_startup_data", + "//third_party/pdfium/testing/fuzzers:pdfium_xfa_fuzzer_src", ] dict = "dicts/pdf.dict" seed_corpus = "//third_party/pdfium/testing/resources" diff --git a/chromium/pdf/pdfium/fuzzers/DEPS b/chromium/pdf/pdfium/fuzzers/DEPS deleted file mode 100644 index aca641cc4dd..00000000000 --- a/chromium/pdf/pdfium/fuzzers/DEPS +++ /dev/null @@ -1,4 +0,0 @@ -include_rules = [ - "+third_party/pdfium/testing/test_support.h", - "+v8/include/v8-platform.h", -] diff --git a/chromium/pdf/pdfium/fuzzers/pdfium_fuzzer.cc b/chromium/pdf/pdfium/fuzzers/pdfium_fuzzer.cc deleted file mode 100644 index 1e8d9c21082..00000000000 --- a/chromium/pdf/pdfium/fuzzers/pdfium_fuzzer.cc +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2017 The Chromium 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 "pdf/pdfium/fuzzers/pdfium_fuzzer_helper.h" - -class PDFiumFuzzer : public PDFiumFuzzerHelper { - public: - PDFiumFuzzer() : PDFiumFuzzerHelper() {} - ~PDFiumFuzzer() override = default; - - int GetFormCallbackVersion() const override { return 1; } -}; - -extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { - PDFiumFuzzer fuzzer; - fuzzer.RenderPdf(reinterpret_cast<const char*>(data), size); - return 0; -} diff --git a/chromium/pdf/pdfium/fuzzers/pdfium_fuzzer_helper.cc b/chromium/pdf/pdfium/fuzzers/pdfium_fuzzer_helper.cc deleted file mode 100644 index ac704de2ffc..00000000000 --- a/chromium/pdf/pdfium/fuzzers/pdfium_fuzzer_helper.cc +++ /dev/null @@ -1,262 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// This fuzzer is simplified & cleaned up pdfium/samples/pdfium_test.cc - -#include "pdf/pdfium/fuzzers/pdfium_fuzzer_helper.h" - -#include <assert.h> -#include <limits.h> - -#include <stddef.h> -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#ifdef _WIN32 -#include <Windows.h> -#elif defined(__APPLE__) -#include <mach-o/dyld.h> -#else // Linux -#include <unistd.h> -#endif // _WIN32 - -#include <memory> -#include <sstream> -#include <string> -#include <utility> - -#include "base/memory/free_deleter.h" -#include "third_party/pdfium/public/cpp/fpdf_scopers.h" -#include "third_party/pdfium/public/fpdf_dataavail.h" -#include "third_party/pdfium/public/fpdf_text.h" -#include "third_party/pdfium/testing/test_support.h" -#include "v8/include/v8-platform.h" - -namespace { - -int ExampleAppAlert(IPDF_JSPLATFORM*, - FPDF_WIDESTRING, - FPDF_WIDESTRING, - int, - int) { - return 0; -} - -int ExampleAppResponse(IPDF_JSPLATFORM*, - FPDF_WIDESTRING question, - FPDF_WIDESTRING title, - FPDF_WIDESTRING default_value, - FPDF_WIDESTRING label, - FPDF_BOOL is_password, - void* response, - int length) { - // UTF-16, always LE regardless of platform. - uint8_t* ptr = static_cast<uint8_t*>(response); - ptr[0] = 'N'; - ptr[1] = 0; - ptr[2] = 'o'; - ptr[3] = 0; - return 4; -} - -void ExampleDocGotoPage(IPDF_JSPLATFORM*, int pageNumber) {} - -void ExampleDocMail(IPDF_JSPLATFORM*, - void* mailData, - int length, - FPDF_BOOL UI, - FPDF_WIDESTRING To, - FPDF_WIDESTRING Subject, - FPDF_WIDESTRING CC, - FPDF_WIDESTRING BCC, - FPDF_WIDESTRING Msg) {} - -void ExampleUnsupportedHandler(UNSUPPORT_INFO*, int type) {} - -FPDF_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) {} - -std::string ProgramPath() { - std::string result; - -#ifdef _WIN32 - wchar_t wpath[MAX_PATH]; - char path[MAX_PATH]; - DWORD len = GetModuleFileNameA(NULL, path, MAX_PATH); - if (len != 0) - result = std::string(path, len); -#elif defined(__APPLE__) - char path[PATH_MAX]; - unsigned int len = PATH_MAX; - if (!_NSGetExecutablePath(path, &len)) { - std::unique_ptr<char, base::FreeDeleter> resolved_path( - realpath(path, nullptr)); - if (resolved_path.get()) - result = std::string(resolved_path.get()); - } -#else // Linux - char path[PATH_MAX]; - ssize_t len = readlink("/proc/self/exe", path, PATH_MAX); - if (len > 0) - result = std::string(path, len); -#endif - return result; -} - -} // namespace - -PDFiumFuzzerHelper::PDFiumFuzzerHelper() = default; - -PDFiumFuzzerHelper::~PDFiumFuzzerHelper() = default; - -bool PDFiumFuzzerHelper::OnFormFillEnvLoaded(FPDF_DOCUMENT doc) { - return true; -} - -void PDFiumFuzzerHelper::RenderPdf(const char* pBuf, size_t len) { - IPDF_JSPLATFORM platform_callbacks; - memset(&platform_callbacks, '\0', sizeof(platform_callbacks)); - platform_callbacks.version = 3; - platform_callbacks.app_alert = ExampleAppAlert; - platform_callbacks.app_response = ExampleAppResponse; - platform_callbacks.Doc_gotoPage = ExampleDocGotoPage; - platform_callbacks.Doc_mail = ExampleDocMail; - - FPDF_FORMFILLINFO form_callbacks; - memset(&form_callbacks, '\0', sizeof(form_callbacks)); - form_callbacks.version = GetFormCallbackVersion(); - form_callbacks.m_pJsPlatform = &platform_callbacks; - - TestLoader loader(pBuf, len); - FPDF_FILEACCESS file_access; - memset(&file_access, '\0', sizeof(file_access)); - file_access.m_FileLen = static_cast<unsigned long>(len); - file_access.m_GetBlock = TestLoader::GetBlock; - file_access.m_Param = &loader; - - FX_FILEAVAIL file_avail; - memset(&file_avail, '\0', sizeof(file_avail)); - file_avail.version = 1; - file_avail.IsDataAvail = Is_Data_Avail; - - FX_DOWNLOADHINTS hints; - memset(&hints, '\0', sizeof(hints)); - hints.version = 1; - hints.AddSegment = Add_Segment; - - ScopedFPDFAvail pdf_avail(FPDFAvail_Create(&file_avail, &file_access)); - - int nRet = PDF_DATA_NOTAVAIL; - bool bIsLinearized = false; - ScopedFPDFDocument doc; - if (FPDFAvail_IsLinearized(pdf_avail.get()) == PDF_LINEARIZED) { - doc.reset(FPDFAvail_GetDocument(pdf_avail.get(), nullptr)); - if (doc) { - while (nRet == PDF_DATA_NOTAVAIL) - nRet = FPDFAvail_IsDocAvail(pdf_avail.get(), &hints); - - if (nRet == PDF_DATA_ERROR) - return; - - nRet = FPDFAvail_IsFormAvail(pdf_avail.get(), &hints); - if (nRet == PDF_FORM_ERROR || nRet == PDF_FORM_NOTAVAIL) - return; - - bIsLinearized = true; - } - } else { - doc.reset(FPDF_LoadCustomDocument(&file_access, nullptr)); - } - - if (!doc) - return; - - (void)FPDF_GetDocPermissions(doc.get()); - - ScopedFPDFFormHandle form( - FPDFDOC_InitFormFillEnvironment(doc.get(), &form_callbacks)); - if (!OnFormFillEnvLoaded(doc.get())) - return; - - FPDF_SetFormFieldHighlightColor(form.get(), FPDF_FORMFIELD_UNKNOWN, 0xFFE4DD); - FPDF_SetFormFieldHighlightAlpha(form.get(), 100); - FORM_DoDocumentJSAction(form.get()); - FORM_DoDocumentOpenAction(form.get()); - - int page_count = FPDF_GetPageCount(doc.get()); - for (int i = 0; i < page_count; ++i) { - if (bIsLinearized) { - nRet = PDF_DATA_NOTAVAIL; - while (nRet == PDF_DATA_NOTAVAIL) - nRet = FPDFAvail_IsPageAvail(pdf_avail.get(), i, &hints); - - if (nRet == PDF_DATA_ERROR) - return; - } - RenderPage(doc.get(), form.get(), i); - } - FORM_DoDocumentAAction(form.get(), FPDFDOC_AACTION_WC); -} - -bool PDFiumFuzzerHelper::RenderPage(FPDF_DOCUMENT doc, - FPDF_FORMHANDLE form, - const int page_index) { - ScopedFPDFPage page(FPDF_LoadPage(doc, page_index)); - if (!page) - return false; - - ScopedFPDFTextPage text_page(FPDFText_LoadPage(page.get())); - FORM_OnAfterLoadPage(page.get(), form); - FORM_DoPageAAction(page.get(), form, FPDFPAGE_AACTION_OPEN); - - const double scale = 1.0; - int width = static_cast<int>(FPDF_GetPageWidth(page.get()) * scale); - int height = static_cast<int>(FPDF_GetPageHeight(page.get()) * scale); - ScopedFPDFBitmap bitmap(FPDFBitmap_Create(width, height, 0)); - if (bitmap) { - FPDFBitmap_FillRect(bitmap.get(), 0, 0, width, height, 0xFFFFFFFF); - FPDF_RenderPageBitmap(bitmap.get(), page.get(), 0, 0, width, height, 0, 0); - FPDF_FFLDraw(form, bitmap.get(), page.get(), 0, 0, width, height, 0, 0); - } - FORM_DoPageAAction(page.get(), form, FPDFPAGE_AACTION_CLOSE); - FORM_OnBeforeClosePage(page.get(), form); - return !!bitmap; -} - -// Initialize the library once for all runs of the fuzzer. -struct TestCase { - TestCase() { -#ifdef V8_USE_EXTERNAL_STARTUP_DATA - platform = InitializeV8ForPDFiumWithStartupData( - ProgramPath(), "", &natives_blob, &snapshot_blob); -#else - platform = InitializeV8ForPDFium(ProgramPath()); -#endif - - memset(&config, '\0', sizeof(config)); - config.version = 2; - config.m_pUserFontPaths = nullptr; - config.m_pIsolate = nullptr; - config.m_v8EmbedderSlot = 0; - FPDF_InitLibraryWithConfig(&config); - - memset(&unsupport_info, '\0', sizeof(unsupport_info)); - unsupport_info.version = 1; - unsupport_info.FSDK_UnSupport_Handler = ExampleUnsupportedHandler; - FSDK_SetUnSpObjProcessHandler(&unsupport_info); - } - - std::unique_ptr<v8::Platform> platform; - v8::StartupData natives_blob; - v8::StartupData snapshot_blob; - FPDF_LIBRARY_CONFIG config; - UNSUPPORT_INFO unsupport_info; -}; - -static TestCase* test_case = new TestCase(); diff --git a/chromium/pdf/pdfium/fuzzers/pdfium_fuzzer_helper.h b/chromium/pdf/pdfium/fuzzers/pdfium_fuzzer_helper.h deleted file mode 100644 index 8a3fe8cac9d..00000000000 --- a/chromium/pdf/pdfium/fuzzers/pdfium_fuzzer_helper.h +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2017 The Chromium 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 PDF_PDFIUM_FUZZERS_PDFIUM_FUZZER_HELPER_H_ -#define PDF_PDFIUM_FUZZERS_PDFIUM_FUZZER_HELPER_H_ - -// This fuzzer is simplified & cleaned up pdfium/samples/pdfium_test.cc - -#include "third_party/pdfium/public/fpdf_ext.h" -#include "third_party/pdfium/public/fpdf_formfill.h" -#include "third_party/pdfium/public/fpdfview.h" -#include "v8/include/v8.h" - -class PDFiumFuzzerHelper { - public: - virtual ~PDFiumFuzzerHelper(); - - void RenderPdf(const char* pBuf, size_t len); - - virtual int GetFormCallbackVersion() const = 0; - virtual bool OnFormFillEnvLoaded(FPDF_DOCUMENT doc); - - protected: - PDFiumFuzzerHelper(); - - private: - bool RenderPage(FPDF_DOCUMENT doc, - FPDF_FORMHANDLE form, - const int page_index); -}; - -#endif // PDF_PDFIUM_FUZZERS_PDFIUM_FUZZER_HELPER_H_ diff --git a/chromium/pdf/pdfium/fuzzers/pdfium_xfa_fuzzer.cc b/chromium/pdf/pdfium/fuzzers/pdfium_xfa_fuzzer.cc deleted file mode 100644 index bac055c83e0..00000000000 --- a/chromium/pdf/pdfium/fuzzers/pdfium_xfa_fuzzer.cc +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2017 The Chromium 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 "pdf/pdfium/fuzzers/pdfium_fuzzer_helper.h" - -class PDFiumXFAFuzzer : public PDFiumFuzzerHelper { - public: - PDFiumXFAFuzzer() : PDFiumFuzzerHelper() {} - ~PDFiumXFAFuzzer() override {} - - int GetFormCallbackVersion() const override { return 2; } - - // Return false if XFA doesn't load as otherwise we're duplicating the work - // done by the non-xfa fuzzer. - bool OnFormFillEnvLoaded(FPDF_DOCUMENT doc) override { - int form_type = FPDF_GetFormType(doc); - if (form_type != FORMTYPE_XFA_FULL && form_type != FORMTYPE_XFA_FOREGROUND) - return false; - return FPDF_LoadXFA(doc); - } -}; - -extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { - PDFiumXFAFuzzer fuzzer; - fuzzer.RenderPdf(reinterpret_cast<const char*>(data), size); - return 0; -} diff --git a/chromium/pdf/pdfium/pdfium_engine.cc b/chromium/pdf/pdfium/pdfium_engine.cc index 5e47623b9ee..80fd5a03f3d 100644 --- a/chromium/pdf/pdfium/pdfium_engine.cc +++ b/chromium/pdf/pdfium/pdfium_engine.cc @@ -76,20 +76,20 @@ static_assert(static_cast<int>(PDFEngine::FormType::kCount) == FORMTYPE_COUNT, namespace { -const int32_t kPageShadowTop = 3; -const int32_t kPageShadowBottom = 7; -const int32_t kPageShadowLeft = 5; -const int32_t kPageShadowRight = 5; +constexpr int32_t kPageShadowTop = 3; +constexpr int32_t kPageShadowBottom = 7; +constexpr int32_t kPageShadowLeft = 5; +constexpr int32_t kPageShadowRight = 5; -const int32_t kPageSeparatorThickness = 4; -const int32_t kHighlightColorR = 153; -const int32_t kHighlightColorG = 193; -const int32_t kHighlightColorB = 218; +constexpr int32_t kPageSeparatorThickness = 4; +constexpr int32_t kHighlightColorR = 153; +constexpr int32_t kHighlightColorG = 193; +constexpr int32_t kHighlightColorB = 218; -const uint32_t kPendingPageColor = 0xFFEEEEEE; +constexpr uint32_t kPendingPageColor = 0xFFEEEEEE; -const uint32_t kFormHighlightColor = 0xFFE4DD; -const int32_t kFormHighlightAlpha = 100; +constexpr uint32_t kFormHighlightColor = 0xFFE4DD; +constexpr int32_t kFormHighlightAlpha = 100; constexpr int kMaxPasswordTries = 3; @@ -105,12 +105,12 @@ constexpr bool kViewerImplementedPanning = true; // See Table 3.20 in // http://www.adobe.com/devnet/acrobat/pdfs/pdf_reference_1-7.pdf -const uint32_t kPDFPermissionPrintLowQualityMask = 1 << 2; -const uint32_t kPDFPermissionPrintHighQualityMask = 1 << 11; -const uint32_t kPDFPermissionCopyMask = 1 << 4; -const uint32_t kPDFPermissionCopyAccessibleMask = 1 << 9; +constexpr uint32_t kPDFPermissionPrintLowQualityMask = 1 << 2; +constexpr uint32_t kPDFPermissionPrintHighQualityMask = 1 << 11; +constexpr uint32_t kPDFPermissionCopyMask = 1 << 4; +constexpr uint32_t kPDFPermissionCopyAccessibleMask = 1 << 9; -const int32_t kLoadingTextVerticalOffset = 50; +constexpr int32_t kLoadingTextVerticalOffset = 50; // The maximum amount of time we'll spend doing a paint before we give back // control of the thread. @@ -131,10 +131,6 @@ constexpr base::TimeDelta kMaxProgressivePaintTime = constexpr base::TimeDelta kMaxInitialProgressivePaintTime = base::TimeDelta::FromMilliseconds(250); -// Flag to turn edit mode tracking on. -// Do not flip until form saving is completely functional. -constexpr bool kIsEditModeTracked = false; - PDFiumEngine* g_engine_for_fontmapper = nullptr; #if defined(OS_LINUX) @@ -147,8 +143,8 @@ PP_BrowserFont_Trusted_Weight WeightToBrowserFontTrustedWeight(int weight) { "PP_BrowserFont_Trusted_Weight min"); static_assert(PP_BROWSERFONT_TRUSTED_WEIGHT_900 == 8, "PP_BrowserFont_Trusted_Weight max"); - const int kMinimumWeight = 100; - const int kMaximumWeight = 900; + constexpr int kMinimumWeight = 100; + constexpr int kMaximumWeight = 900; int normalized_weight = std::min(std::max(weight, kMinimumWeight), kMaximumWeight); normalized_weight = (normalized_weight / 100) - 1; @@ -240,7 +236,7 @@ void* MapFont(FPDF_SYSFONTINFO*, // Map from the standard PDF fonts to TrueType font names. size_t i; - for (i = 0; i < arraysize(kPdfFontSubstitutions); ++i) { + for (i = 0; i < base::size(kPdfFontSubstitutions); ++i) { if (strcmp(face, kPdfFontSubstitutions[i].pdf_name) == 0) { description.set_face(kPdfFontSubstitutions[i].face); if (kPdfFontSubstitutions[i].bold) @@ -251,7 +247,7 @@ void* MapFont(FPDF_SYSFONTINFO*, } } - if (i == arraysize(kPdfFontSubstitutions)) { + if (i == base::size(kPdfFontSubstitutions)) { // Convert to UTF-8 before calling set_face(). std::string face_utf8; if (base::IsStringUTF8(face)) { @@ -447,7 +443,7 @@ void FormatStringWithHyphens(base::string16* text) { std::vector<HyphenPosition> hyphen_positions; HyphenPosition current_hyphen_position; bool current_hyphen_position_is_valid = false; - const base::char16 kPdfiumHyphenEOL = 0xfffe; + constexpr base::char16 kPdfiumHyphenEOL = 0xfffe; for (size_t i = 0; i < text->size(); ++i) { const base::char16& current_char = (*text)[i]; @@ -471,7 +467,7 @@ void FormatStringWithHyphens(base::string16* text) { // With all the hyphen positions, do the search and replace. while (!hyphen_positions.empty()) { - static const base::char16 kCr[] = {L'\r', L'\0'}; + static constexpr base::char16 kCr[] = {L'\r', L'\0'}; const HyphenPosition& position = hyphen_positions.back(); if (position.next_whitespace_position != 0) { (*text)[position.next_whitespace_position] = L'\n'; @@ -482,16 +478,16 @@ void FormatStringWithHyphens(base::string16* text) { } // Adobe Reader also get rid of trailing spaces right before a CRLF. - static const base::char16 kSpaceCrCn[] = {L' ', L'\r', L'\n', L'\0'}; - static const base::char16 kCrCn[] = {L'\r', L'\n', L'\0'}; + static constexpr base::char16 kSpaceCrCn[] = {L' ', L'\r', L'\n', L'\0'}; + static constexpr base::char16 kCrCn[] = {L'\r', L'\n', L'\0'}; base::ReplaceSubstringsAfterOffset(text, 0, kSpaceCrCn, kCrCn); } // Replace CR/LF with just LF on POSIX. void FormatStringForOS(base::string16* text) { #if defined(OS_POSIX) - static const base::char16 kCr[] = {L'\r', L'\0'}; - static const base::char16 kBlank[] = {L'\0'}; + static constexpr base::char16 kCr[] = {L'\r', L'\0'}; + static constexpr base::char16 kBlank[] = {L'\0'}; base::ReplaceChars(*text, kCr, kBlank, text); #elif defined(OS_WIN) // Do nothing @@ -515,7 +511,6 @@ bool FindMultipleClickBoundary(bool is_double_click, base::char16 cur) { if (cur < 128) return true; - static constexpr base::char16 kZeroWidthSpace = 0x200B; if (cur == kZeroWidthSpace) return true; @@ -891,6 +886,13 @@ std::string PDFiumEngine::GetMetadata(const std::string& key) { return GetDocumentMetadata(doc(), key); } +std::vector<uint8_t> PDFiumEngine::GetSaveData() { + PDFiumMemBufferFileWrite output_file_write; + if (!FPDF_SaveAsCopy(doc(), &output_file_write, 0)) + return std::vector<uint8_t>(); + return output_file_write.TakeBuffer(); +} + void PDFiumEngine::OnPendingRequestComplete() { if (!process_when_pending_request_complete_) return; @@ -1125,17 +1127,17 @@ pp::Resource PDFiumEngine::PrintPages( if ((print_settings.format & PP_PRINTOUTPUTFORMAT_PDF) && HasPermission(PERMISSION_PRINT_HIGH_QUALITY)) { - return PrintPagesAsPDF(page_ranges, page_range_count, print_settings, + return PrintPagesAsPdf(page_ranges, page_range_count, print_settings, pdf_print_settings); } if (HasPermission(PERMISSION_PRINT_LOW_QUALITY)) { - return PrintPagesAsRasterPDF(page_ranges, page_range_count, print_settings, + return PrintPagesAsRasterPdf(page_ranges, page_range_count, print_settings, pdf_print_settings); } return pp::Resource(); } -pp::Buffer_Dev PDFiumEngine::PrintPagesAsRasterPDF( +pp::Buffer_Dev PDFiumEngine::PrintPagesAsRasterPdf( const PP_PrintPageNumberRange_Dev* page_ranges, uint32_t page_range_count, const PP_PrintSettings_Dev& print_settings, @@ -1152,11 +1154,12 @@ pp::Buffer_Dev PDFiumEngine::PrintPagesAsRasterPDF( g_last_instance_id = client_->GetPluginInstance()->pp_instance(); #endif - return print_.PrintPagesAsRasterPDF(page_ranges, page_range_count, - print_settings, pdf_print_settings); + return ConvertPdfToBufferDev( + print_.PrintPagesAsPdf(page_ranges, page_range_count, print_settings, + pdf_print_settings, /*raster=*/true)); } -pp::Buffer_Dev PDFiumEngine::PrintPagesAsPDF( +pp::Buffer_Dev PDFiumEngine::PrintPagesAsPdf( const PP_PrintPageNumberRange_Dev* page_ranges, uint32_t page_range_count, const PP_PrintSettings_Dev& print_settings, @@ -1175,8 +1178,20 @@ pp::Buffer_Dev PDFiumEngine::PrintPagesAsPDF( pages_[page_number]->Unload(); } - return print_.PrintPagesAsPDF(page_ranges, page_range_count, print_settings, - pdf_print_settings); + return ConvertPdfToBufferDev( + print_.PrintPagesAsPdf(page_ranges, page_range_count, print_settings, + pdf_print_settings, /*raster=*/false)); +} + +pp::Buffer_Dev PDFiumEngine::ConvertPdfToBufferDev( + const std::vector<uint8_t>& pdf_data) { + pp::Buffer_Dev buffer; + if (!pdf_data.empty()) { + buffer = pp::Buffer_Dev(GetPluginInstance(), pdf_data.size()); + if (!buffer.is_null()) + memcpy(buffer.data(), pdf_data.data(), pdf_data.size()); + } + return buffer; } void PDFiumEngine::KillFormFocus() { @@ -1919,28 +1934,88 @@ void PDFiumEngine::SearchUsingICU(const base::string16& term, character_to_start_searching_from, text_length, data); api_string_adapter.Close(written); + base::string16 adjusted_page_text; + adjusted_page_text.reserve(page_text.size()); + // Values in |removed_indices| are in the adjusted text index space and + // indicate a character was removed from the page text before the given + // index. If multiple characters are removed in a row then there will be + // multiple entries with the same value. + std::vector<size_t> removed_indices; + // When walking through the page text collapse any whitespace regions, + // including \r and \n, down to a single ' ' character. This code does + // not use base::CollapseWhitespace(), because that function does not + // return where the collapsing occurs, but uses the same underlying list of + // whitespace characters. Calculating where the collapsed regions are after + // the fact is as complex as collapsing them manually. + for (size_t i = 0; i < page_text.size(); i++) { + base::char16 c = page_text[i]; + // Collapse whitespace regions by inserting a ' ' into the + // adjusted text and recording any removed whitespace indices as preceding + // it. + if (base::IsUnicodeWhitespace(c)) { + size_t whitespace_region_begin = i; + while (i < page_text.size() && base::IsUnicodeWhitespace(page_text[i])) + ++i; + + size_t count = i - whitespace_region_begin - 1; + removed_indices.insert(removed_indices.end(), count, + adjusted_page_text.size()); + adjusted_page_text.push_back(' '); + if (i >= page_text.size()) + break; + c = page_text[i]; + } + + if (IsIgnorableCharacter(c)) + removed_indices.push_back(adjusted_page_text.size()); + else + adjusted_page_text.push_back(c); + } + std::vector<PDFEngine::Client::SearchStringResult> results = - client_->SearchString(page_text.c_str(), term.c_str(), case_sensitive); + client_->SearchString(adjusted_page_text.c_str(), term.c_str(), + case_sensitive); for (const auto& result : results) { + // Need to convert from adjusted page text start to page text start, by + // incrementing for all the characters adjusted before it in the string. + auto removed_indices_begin = std::upper_bound( + removed_indices.begin(), removed_indices.end(), result.start_index); + size_t page_text_result_start_index = + result.start_index + + std::distance(removed_indices.begin(), removed_indices_begin); + + // Need to convert the adjusted page length into a page text length, since + // the matching range may have adjusted characters within it. This + // conversion only cares about skipped characters in the result interval. + auto removed_indices_end = + std::upper_bound(removed_indices_begin, removed_indices.end(), + result.start_index + result.length); + int term_removed_count = + std::distance(removed_indices_begin, removed_indices_end); + int page_text_result_length = result.length + term_removed_count; + // Need to map the indexes from the page text, which may have generated // characters like space etc, to character indices from the page. int text_to_start_searching_from = FPDFText_GetTextIndexFromCharIndex( pages_[current_page]->GetTextPage(), character_to_start_searching_from); - int temp_start = result.start_index + text_to_start_searching_from; + int temp_start = + page_text_result_start_index + text_to_start_searching_from; int start = FPDFText_GetCharIndexFromTextIndex( pages_[current_page]->GetTextPage(), temp_start); int end = FPDFText_GetCharIndexFromTextIndex( - pages_[current_page]->GetTextPage(), temp_start + result.length); + pages_[current_page]->GetTextPage(), + temp_start + page_text_result_length); // If |term| occurs at the end of a page, then |end| will be -1 due to the // index being out of bounds. Compensate for this case so the range // character count calculation below works out. - if (temp_start + result.length == original_text_length) { + if (temp_start + page_text_result_length == original_text_length) { DCHECK_EQ(-1, end); end = original_text_length; } DCHECK_LT(start, end); - DCHECK_EQ(term.size(), static_cast<size_t>(end - start)); + DCHECK_EQ(term.size() + term_removed_count, + static_cast<size_t>(end - start)); AddFindResult(PDFiumRange(pages_[current_page].get(), start, end - start)); } } @@ -2275,7 +2350,7 @@ pp::VarDictionary PDFiumEngine::TraverseBookmarks(FPDF_BOOKMARK bookmark, pp::VarArray children; // Don't trust PDFium to handle circular bookmarks. - const unsigned int kMaxDepth = 128; + constexpr unsigned int kMaxDepth = 128; if (depth < kMaxDepth) { int child_index = 0; std::set<FPDF_BOOKMARK> seen_bookmarks; @@ -3363,7 +3438,7 @@ void PDFiumEngine::DrawPageShadow(const pp::Rect& page_rc, clip_rect.Offset(page_offset_); // Page drop shadow parameters. - const double factor = 0.5; + constexpr double factor = 0.5; uint32_t depth = std::max(std::max(page_rect.x() - shadow_rect.x(), page_rect.y() - shadow_rect.y()), @@ -3469,7 +3544,7 @@ void PDFiumEngine::SetSelecting(bool selecting) { } void PDFiumEngine::SetEditMode(bool edit_mode) { - if (!kIsEditModeTracked || edit_mode_ == edit_mode) + if (edit_mode_ == edit_mode) return; edit_mode_ = edit_mode; diff --git a/chromium/pdf/pdfium/pdfium_engine.h b/chromium/pdf/pdfium/pdfium_engine.h index 5bc0029ca13..4d931205046 100644 --- a/chromium/pdf/pdfium/pdfium_engine.h +++ b/chromium/pdf/pdfium/pdfium_engine.h @@ -119,6 +119,7 @@ class PDFiumEngine : public PDFEngine, void AppendBlankPages(int num_pages) override; void AppendPage(PDFEngine* engine, int index) override; std::string GetMetadata(const std::string& key) override; + std::vector<uint8_t> GetSaveData() override; void SetCaretPosition(const pp::Point& position) override; void MoveRangeSelectionExtent(const pp::Point& extent) override; void SetSelectionBounds(const pp::Point& base, @@ -300,18 +301,20 @@ class PDFiumEngine : public PDFEngine, bool ExtendSelection(int page_index, int char_index); - pp::Buffer_Dev PrintPagesAsRasterPDF( + pp::Buffer_Dev PrintPagesAsRasterPdf( const PP_PrintPageNumberRange_Dev* page_ranges, uint32_t page_range_count, const PP_PrintSettings_Dev& print_settings, const PP_PdfPrintSettings_Dev& pdf_print_settings); - pp::Buffer_Dev PrintPagesAsPDF( + pp::Buffer_Dev PrintPagesAsPdf( const PP_PrintPageNumberRange_Dev* page_ranges, uint32_t page_range_count, const PP_PrintSettings_Dev& print_settings, const PP_PdfPrintSettings_Dev& pdf_print_settings); + pp::Buffer_Dev ConvertPdfToBufferDev(const std::vector<uint8_t>& pdf_data); + // Checks if |page| has selected text in a form element. If so, sets that as // the plugin's text selection. void SetFormSelectedText(FPDF_FORMHANDLE form_handle, FPDF_PAGE page); diff --git a/chromium/pdf/pdfium/pdfium_engine_exports.cc b/chromium/pdf/pdfium/pdfium_engine_exports.cc index 8b5f69b6c27..e0465a84911 100644 --- a/chromium/pdf/pdfium/pdfium_engine_exports.cc +++ b/chromium/pdf/pdfium/pdfium_engine_exports.cc @@ -16,6 +16,7 @@ #include "third_party/pdfium/public/cpp/fpdf_scopers.h" #include "third_party/pdfium/public/fpdf_ppo.h" #include "third_party/pdfium/public/fpdfview.h" +#include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/size.h" using printing::ConvertUnitDouble; @@ -119,31 +120,12 @@ ScopedFPDFDocument CreatePdfDoc( return doc; } -std::vector<uint8_t> CreateNupPdfDocument(FPDF_DOCUMENT doc, - size_t pages_per_sheet, - const gfx::Size& page_size) { - int page_size_width = page_size.width(); - int page_size_height = page_size.height(); - - printing::NupParameters nup_params; - bool is_landscape = PDFiumPrint::IsSourcePdfLandscape(doc); - nup_params.SetParameters(pages_per_sheet, is_landscape); - bool paper_is_landscape = page_size_width > page_size_height; - if (nup_params.landscape() != paper_is_landscape) - std::swap(page_size_width, page_size_height); - - ScopedFPDFDocument output_doc_nup(FPDF_ImportNPagesToOne( - doc, page_size_width, page_size_height, nup_params.num_pages_on_x_axis(), - nup_params.num_pages_on_y_axis())); - - if (!output_doc_nup) - return std::vector<uint8_t>(); - - PDFiumMemBufferFileWrite output_file_write; - if (!FPDF_SaveAsCopy(output_doc_nup.get(), &output_file_write, 0)) - return std::vector<uint8_t>(); - - return output_file_write.TakeBuffer(); +bool IsValidPrintableArea(const gfx::Size& page_size, + const gfx::Rect& printable_area) { + return !printable_area.IsEmpty() && printable_area.x() >= 0 && + printable_area.y() >= 0 && + printable_area.right() <= page_size.width() && + printable_area.bottom() <= page_size.height(); } } // namespace @@ -302,23 +284,33 @@ bool PDFiumEngineExports::RenderPDFPageToBitmap( std::vector<uint8_t> PDFiumEngineExports::ConvertPdfPagesToNupPdf( std::vector<base::span<const uint8_t>> input_buffers, size_t pages_per_sheet, - const gfx::Size& page_size) { + const gfx::Size& page_size, + const gfx::Rect& printable_area) { + if (!IsValidPrintableArea(page_size, printable_area)) + return std::vector<uint8_t>(); + ScopedFPDFDocument doc = CreatePdfDoc(std::move(input_buffers)); if (!doc) return std::vector<uint8_t>(); - return CreateNupPdfDocument(doc.get(), pages_per_sheet, page_size); + return PDFiumPrint::CreateNupPdf(std::move(doc), pages_per_sheet, page_size, + printable_area); } std::vector<uint8_t> PDFiumEngineExports::ConvertPdfDocumentToNupPdf( base::span<const uint8_t> input_buffer, size_t pages_per_sheet, - const gfx::Size& page_size) { + const gfx::Size& page_size, + const gfx::Rect& printable_area) { + if (!IsValidPrintableArea(page_size, printable_area)) + return std::vector<uint8_t>(); + ScopedFPDFDocument doc = LoadPdfData(input_buffer); if (!doc) return std::vector<uint8_t>(); - return CreateNupPdfDocument(doc.get(), pages_per_sheet, page_size); + return PDFiumPrint::CreateNupPdf(std::move(doc), pages_per_sheet, page_size, + printable_area); } bool PDFiumEngineExports::GetPDFDocInfo(base::span<const uint8_t> pdf_buffer, diff --git a/chromium/pdf/pdfium/pdfium_engine_exports.h b/chromium/pdf/pdfium/pdfium_engine_exports.h index 04de13d66c0..02832594bc0 100644 --- a/chromium/pdf/pdfium/pdfium_engine_exports.h +++ b/chromium/pdf/pdfium/pdfium_engine_exports.h @@ -8,7 +8,6 @@ #include <stddef.h> #include <stdint.h> -#include "base/containers/span.h" #include "build/build_config.h" #include "pdf/pdf_engine.h" @@ -38,11 +37,13 @@ class PDFiumEngineExports : public PDFEngineExports { std::vector<uint8_t> ConvertPdfPagesToNupPdf( std::vector<base::span<const uint8_t>> input_buffers, size_t pages_per_sheet, - const gfx::Size& page_size) override; + const gfx::Size& page_size, + const gfx::Rect& printable_area) override; std::vector<uint8_t> ConvertPdfDocumentToNupPdf( base::span<const uint8_t> input_buffer, size_t pages_per_sheet, - const gfx::Size& page_size) override; + const gfx::Size& page_size, + const gfx::Rect& printable_area) override; bool GetPDFDocInfo(base::span<const uint8_t> pdf_buffer, int* page_count, double* max_page_width) override; diff --git a/chromium/pdf/pdfium/pdfium_engine_exports_unittest.cc b/chromium/pdf/pdfium/pdfium_engine_exports_unittest.cc index ab01ba13e8b..ed3e31c39ab 100644 --- a/chromium/pdf/pdfium/pdfium_engine_exports_unittest.cc +++ b/chromium/pdf/pdfium/pdfium_engine_exports_unittest.cc @@ -10,6 +10,7 @@ #include "pdf/pdf.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" +#include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/size.h" namespace chrome_pdf { @@ -102,14 +103,26 @@ TEST_F(PDFiumEngineExportsTest, ConvertPdfPagesToNupPdf) { ASSERT_TRUE(base::ReadFileToString(pdf_path, &pdf_data)); std::vector<base::span<const uint8_t>> pdf_buffers; - std::vector<uint8_t> output_pdf_buffer = - ConvertPdfPagesToNupPdf(pdf_buffers, 1, gfx::Size(512, 792)); + std::vector<uint8_t> output_pdf_buffer = ConvertPdfPagesToNupPdf( + pdf_buffers, 1, gfx::Size(612, 792), gfx::Rect(22, 20, 570, 750)); EXPECT_TRUE(output_pdf_buffer.empty()); pdf_buffers.push_back(base::as_bytes(base::make_span(pdf_data))); pdf_buffers.push_back(base::as_bytes(base::make_span(pdf_data))); - output_pdf_buffer = - ConvertPdfPagesToNupPdf(pdf_buffers, 2, gfx::Size(512, 792)); + output_pdf_buffer = ConvertPdfPagesToNupPdf( + pdf_buffers, 2, gfx::Size(612, 792), gfx::Rect(22, 20, 0, 750)); + EXPECT_TRUE(output_pdf_buffer.empty()); + output_pdf_buffer = ConvertPdfPagesToNupPdf( + pdf_buffers, 2, gfx::Size(612, 792), gfx::Rect(22, 20, 570, 0)); + EXPECT_TRUE(output_pdf_buffer.empty()); + output_pdf_buffer = ConvertPdfPagesToNupPdf( + pdf_buffers, 2, gfx::Size(612, 792), gfx::Rect(300, 20, 570, 750)); + EXPECT_TRUE(output_pdf_buffer.empty()); + output_pdf_buffer = ConvertPdfPagesToNupPdf( + pdf_buffers, 2, gfx::Size(612, 792), gfx::Rect(22, 400, 570, 750)); + EXPECT_TRUE(output_pdf_buffer.empty()); + output_pdf_buffer = ConvertPdfPagesToNupPdf( + pdf_buffers, 2, gfx::Size(612, 792), gfx::Rect(22, 20, 570, 750)); ASSERT_GT(output_pdf_buffer.size(), 0U); base::span<const uint8_t> output_pdf_span = @@ -122,7 +135,7 @@ TEST_F(PDFiumEngineExportsTest, ConvertPdfPagesToNupPdf) { double height; ASSERT_TRUE(GetPDFPageSizeByIndex(output_pdf_span, 0, &width, &height)); EXPECT_DOUBLE_EQ(792.0, width); - EXPECT_DOUBLE_EQ(512.0, height); + EXPECT_DOUBLE_EQ(612.0, height); } TEST_F(PDFiumEngineExportsTest, ConvertPdfDocumentToNupPdf) { @@ -132,13 +145,13 @@ TEST_F(PDFiumEngineExportsTest, ConvertPdfDocumentToNupPdf) { ASSERT_TRUE(base::ReadFileToString(pdf_path, &pdf_data)); base::span<const uint8_t> pdf_buffer; - std::vector<uint8_t> output_pdf_buffer = - ConvertPdfDocumentToNupPdf(pdf_buffer, 1, gfx::Size(512, 792)); + std::vector<uint8_t> output_pdf_buffer = ConvertPdfDocumentToNupPdf( + pdf_buffer, 1, gfx::Size(612, 792), gfx::Rect(32, 20, 570, 750)); EXPECT_TRUE(output_pdf_buffer.empty()); pdf_buffer = base::as_bytes(base::make_span(pdf_data)); - output_pdf_buffer = - ConvertPdfDocumentToNupPdf(pdf_buffer, 4, gfx::Size(512, 792)); + output_pdf_buffer = ConvertPdfDocumentToNupPdf( + pdf_buffer, 4, gfx::Size(612, 792), gfx::Rect(22, 20, 570, 750)); ASSERT_GT(output_pdf_buffer.size(), 0U); base::span<const uint8_t> output_pdf_span = @@ -151,7 +164,7 @@ TEST_F(PDFiumEngineExportsTest, ConvertPdfDocumentToNupPdf) { double height; ASSERT_TRUE( GetPDFPageSizeByIndex(output_pdf_span, page_number, &width, &height)); - EXPECT_DOUBLE_EQ(512.0, width); + EXPECT_DOUBLE_EQ(612.0, width); EXPECT_DOUBLE_EQ(792.0, height); } } diff --git a/chromium/pdf/pdfium/pdfium_mem_buffer_file_write.h b/chromium/pdf/pdfium/pdfium_mem_buffer_file_write.h index 03c54bb6380..82e82d23684 100644 --- a/chromium/pdf/pdfium/pdfium_mem_buffer_file_write.h +++ b/chromium/pdf/pdfium/pdfium_mem_buffer_file_write.h @@ -6,6 +6,7 @@ #define PDF_PDFIUM_PDFIUM_MEM_BUFFER_FILE_WRITE_H_ #include <stddef.h> +#include <stdint.h> #include <vector> diff --git a/chromium/pdf/pdfium/pdfium_page.cc b/chromium/pdf/pdfium/pdfium_page.cc index 37b4db3dfe7..941b8594268 100644 --- a/chromium/pdf/pdfium/pdfium_page.cc +++ b/chromium/pdf/pdfium/pdfium_page.cc @@ -134,26 +134,6 @@ FPDF_PAGE PDFiumPage::GetPage() { return page(); } -FPDF_PAGE PDFiumPage::GetPrintPage() { - ScopedUnsupportedFeature scoped_unsupported_feature(engine_); - ScopedSubstFont scoped_subst_font(engine_); - if (!available_) - return nullptr; - if (!page_) { - ScopedUnloadPreventer scoped_unload_preventer(this); - page_.reset(FPDF_LoadPage(engine_->doc(), index_)); - } - return page(); -} - -void PDFiumPage::ClosePrintPage() { - // Do not close |page_| while in the middle of a load. - if (preventing_unload_count_) - return; - - page_.reset(); -} - FPDF_TEXTPAGE PDFiumPage::GetTextPage() { if (!available_) return nullptr; diff --git a/chromium/pdf/pdfium/pdfium_page.h b/chromium/pdf/pdfium/pdfium_page.h index 86daadc0ed5..ae9b186c101 100644 --- a/chromium/pdf/pdfium/pdfium_page.h +++ b/chromium/pdf/pdfium/pdfium_page.h @@ -33,10 +33,6 @@ class PDFiumPage { void Unload(); // Gets the FPDF_PAGE for this page, loading and parsing it if necessary. FPDF_PAGE GetPage(); - // Get the FPDF_PAGE for printing. - FPDF_PAGE GetPrintPage(); - // Close the printing page. - void ClosePrintPage(); // Returns FPDF_TEXTPAGE for the page, loading and parsing it if necessary. FPDF_TEXTPAGE GetTextPage(); diff --git a/chromium/pdf/pdfium/pdfium_print.cc b/chromium/pdf/pdfium/pdfium_print.cc index 037cfd4660c..73e034ca9d6 100644 --- a/chromium/pdf/pdfium/pdfium_print.cc +++ b/chromium/pdf/pdfium/pdfium_print.cc @@ -4,6 +4,7 @@ #include "pdf/pdfium/pdfium_print.h" +#include <algorithm> #include <string> #include <utility> @@ -15,13 +16,14 @@ #include "ppapi/c/dev/ppp_printing_dev.h" #include "ppapi/c/private/ppp_pdf.h" #include "printing/nup_parameters.h" +#include "printing/page_setup.h" #include "printing/units.h" -#include "third_party/pdfium/public/cpp/fpdf_scopers.h" #include "third_party/pdfium/public/fpdf_flatten.h" #include "third_party/pdfium/public/fpdf_ppo.h" #include "third_party/pdfium/public/fpdf_transformpage.h" #include "ui/gfx/codec/jpeg_codec.h" #include "ui/gfx/geometry/rect.h" +#include "ui/gfx/geometry/size.h" using printing::ConvertUnit; using printing::ConvertUnitDouble; @@ -37,6 +39,11 @@ bool ShouldDoNup(int pages_per_sheet) { return pages_per_sheet > 1; } +// Returns the valid, positive page count, or 0 on failure. +int GetDocumentPageCount(FPDF_DOCUMENT doc) { + return std::max(FPDF_GetPageCount(doc), 0); +} + // Set the destination page size and content area in points based on source // page rotation and orientation. // @@ -165,6 +172,45 @@ void FitContentsToPrintableAreaIfRequired( } } +// Takes the same parameters as PDFiumPrint::CreateNupPdf(). +// On success, returns the N-up version of |doc|. On failure, returns nullptr. +ScopedFPDFDocument CreateNupPdfDocument(ScopedFPDFDocument doc, + size_t pages_per_sheet, + const gfx::Size& page_size, + const gfx::Rect& printable_area) { + DCHECK(doc); + DCHECK(ShouldDoNup(pages_per_sheet)); + + int page_size_width = page_size.width(); + int page_size_height = page_size.height(); + + printing::NupParameters nup_params; + bool is_landscape = PDFiumPrint::IsSourcePdfLandscape(doc.get()); + nup_params.SetParameters(pages_per_sheet, is_landscape); + bool paper_is_landscape = page_size_width > page_size_height; + if (nup_params.landscape() != paper_is_landscape) + std::swap(page_size_width, page_size_height); + + ScopedFPDFDocument nup_doc(FPDF_ImportNPagesToOne( + doc.get(), page_size_width, page_size_height, + nup_params.num_pages_on_x_axis(), nup_params.num_pages_on_y_axis())); + if (nup_doc) { + PDFiumPrint::FitContentsToPrintableArea(nup_doc.get(), page_size, + printable_area); + } + return nup_doc; +} + +std::vector<uint8_t> ConvertDocToBuffer(ScopedFPDFDocument doc) { + DCHECK(doc); + + std::vector<uint8_t> buffer; + PDFiumMemBufferFileWrite output_file_write; + if (FPDF_SaveAsCopy(doc.get(), &output_file_write, 0)) + buffer = output_file_write.TakeBuffer(); + return buffer; +} + int GetBlockForJpeg(void* param, unsigned long pos, unsigned char* buf, @@ -217,6 +263,20 @@ std::vector<uint32_t> PDFiumPrint::GetPageNumbersFromPrintPageNumberRange( return page_numbers; } +// static +std::vector<uint8_t> PDFiumPrint::CreateNupPdf( + ScopedFPDFDocument doc, + size_t pages_per_sheet, + const gfx::Size& page_size, + const gfx::Rect& printable_area) { + ScopedFPDFDocument nup_doc = CreateNupPdfDocument( + std::move(doc), pages_per_sheet, page_size, printable_area); + if (!nup_doc) + return std::vector<uint8_t>(); + return ConvertDocToBuffer(std::move(nup_doc)); +} + +// static bool PDFiumPrint::IsSourcePdfLandscape(FPDF_DOCUMENT doc) { DCHECK(doc); @@ -228,80 +288,37 @@ bool PDFiumPrint::IsSourcePdfLandscape(FPDF_DOCUMENT doc) { return is_source_landscape; } -pp::Buffer_Dev PDFiumPrint::PrintPagesAsRasterPDF( +// static +void PDFiumPrint::FitContentsToPrintableArea(FPDF_DOCUMENT doc, + const gfx::Size& page_size, + const gfx::Rect& printable_area) { + PP_PrintSettings_Dev print_settings; + print_settings.paper_size = pp::Size(page_size.width(), page_size.height()); + print_settings.printable_area = + pp::Rect(printable_area.x(), printable_area.y(), printable_area.width(), + printable_area.height()); + print_settings.print_scaling_option = + PP_PRINTSCALINGOPTION_FIT_TO_PRINTABLE_AREA; + FitContentsToPrintableAreaIfRequired(doc, 1.0, print_settings); +} + +std::vector<uint8_t> PDFiumPrint::PrintPagesAsPdf( const PP_PrintPageNumberRange_Dev* page_ranges, uint32_t page_range_count, const PP_PrintSettings_Dev& print_settings, - const PP_PdfPrintSettings_Dev& pdf_print_settings) { - std::vector<PDFiumPage> pages_to_print; - // width and height of source PDF pages. - std::vector<std::pair<double, double>> source_page_sizes; - // Collect pages to print and sizes of source pages. - std::vector<uint32_t> page_numbers = - PDFiumPrint::GetPageNumbersFromPrintPageNumberRange(page_ranges, - page_range_count); - for (uint32_t page_number : page_numbers) { - ScopedFPDFPage pdf_page(FPDF_LoadPage(engine_->doc(), page_number)); - double source_page_width = FPDF_GetPageWidth(pdf_page.get()); - double source_page_height = FPDF_GetPageHeight(pdf_page.get()); - source_page_sizes.push_back( - std::make_pair(source_page_width, source_page_height)); - // For computing size in pixels, use a square dpi since the source PDF page - // has square DPI. - int width_in_pixels = - ConvertUnit(source_page_width, kPointsPerInch, print_settings.dpi); - int height_in_pixels = - ConvertUnit(source_page_height, kPointsPerInch, print_settings.dpi); - - pp::Rect rect(width_in_pixels, height_in_pixels); - pages_to_print.push_back(PDFiumPage(engine_, page_number, rect, true)); - } - - ScopedFPDFDocument output_doc(FPDF_CreateNewDocument()); - DCHECK(output_doc); - - size_t i = 0; - for (; i < pages_to_print.size(); ++i) { - double source_page_width = source_page_sizes[i].first; - double source_page_height = source_page_sizes[i].second; - - // Use |temp_doc| to compress image by saving PDF to |buffer|. - pp::Buffer_Dev buffer; - { - ScopedFPDFDocument temp_doc( - CreateSinglePageRasterPdf(source_page_width, source_page_height, - print_settings, &pages_to_print[i])); - - if (!temp_doc) - break; - - buffer = GetFlattenedPrintData(temp_doc.get()); - } - - PDFiumMemBufferFileRead file_read(buffer.data(), buffer.size()); - ScopedFPDFDocument temp_doc(FPDF_LoadCustomDocument(&file_read, nullptr)); - if (!FPDF_ImportPages(output_doc.get(), temp_doc.get(), "1", i)) - break; - } - - pp::Buffer_Dev buffer; - if (i == pages_to_print.size()) { - FPDF_CopyViewerPreferences(output_doc.get(), engine_->doc()); - uint32_t pages_per_sheet = pdf_print_settings.pages_per_sheet; - uint32_t scale_factor = pdf_print_settings.scale_factor; - if (ShouldDoNup(pages_per_sheet)) { - buffer = NupPdfToPdf(output_doc.get(), pages_per_sheet, print_settings); - } else { - FitContentsToPrintableAreaIfRequired( - output_doc.get(), scale_factor / 100.0f, print_settings); - buffer = GetPrintData(output_doc.get()); - } - } - + const PP_PdfPrintSettings_Dev& pdf_print_settings, + bool raster) { + std::vector<uint8_t> buffer; + ScopedFPDFDocument output_doc = CreatePrintPdf( + page_ranges, page_range_count, print_settings, pdf_print_settings); + if (raster) + output_doc = CreateRasterPdf(std::move(output_doc), print_settings); + if (GetDocumentPageCount(output_doc.get())) + buffer = ConvertDocToBuffer(std::move(output_doc)); return buffer; } -pp::Buffer_Dev PDFiumPrint::PrintPagesAsPDF( +ScopedFPDFDocument PDFiumPrint::CreatePrintPdf( const PP_PrintPageNumberRange_Dev* page_ranges, uint32_t page_range_count, const PP_PrintSettings_Dev& print_settings, @@ -314,59 +331,90 @@ pp::Buffer_Dev PDFiumPrint::PrintPagesAsPDF( GetPageRangeStringFromRange(page_ranges, page_range_count); if (!FPDF_ImportPages(output_doc.get(), engine_->doc(), page_number_str.c_str(), 0)) { - return pp::Buffer_Dev(); + return nullptr; } - pp::Buffer_Dev buffer; + double scale_factor = pdf_print_settings.scale_factor / 100.0; + FitContentsToPrintableAreaIfRequired(output_doc.get(), scale_factor, + print_settings); + if (!FlattenPrintData(output_doc.get())) + return nullptr; + uint32_t pages_per_sheet = pdf_print_settings.pages_per_sheet; - uint32_t scale_factor = pdf_print_settings.scale_factor; - if (ShouldDoNup(pages_per_sheet)) { - if (FlattenPrintData(output_doc.get())) - buffer = NupPdfToPdf(output_doc.get(), pages_per_sheet, print_settings); - } else { - FitContentsToPrintableAreaIfRequired(output_doc.get(), - scale_factor / 100.0f, print_settings); - if (FlattenPrintData(output_doc.get())) - buffer = GetPrintData(output_doc.get()); + if (!ShouldDoNup(pages_per_sheet)) + return output_doc; + + gfx::Size page_size(print_settings.paper_size.width, + print_settings.paper_size.height); + gfx::Rect printable_area(print_settings.printable_area.point.x, + print_settings.printable_area.point.y, + print_settings.printable_area.size.width, + print_settings.printable_area.size.height); + gfx::Rect symmetrical_printable_area = + printing::PageSetup::GetSymmetricalPrintableArea(page_size, + printable_area); + if (symmetrical_printable_area.IsEmpty()) + return nullptr; + return CreateNupPdfDocument(std::move(output_doc), pages_per_sheet, page_size, + symmetrical_printable_area); +} + +ScopedFPDFDocument PDFiumPrint::CreateRasterPdf( + ScopedFPDFDocument doc, + const PP_PrintSettings_Dev& print_settings) { + int page_count = GetDocumentPageCount(doc.get()); + if (page_count == 0) + return nullptr; + + ScopedFPDFDocument rasterized_doc(FPDF_CreateNewDocument()); + DCHECK(rasterized_doc); + FPDF_CopyViewerPreferences(rasterized_doc.get(), doc.get()); + + for (int i = 0; i < page_count; ++i) { + ScopedFPDFPage pdf_page(FPDF_LoadPage(doc.get(), i)); + if (!pdf_page) + return nullptr; + + ScopedFPDFDocument temp_doc = + CreateSinglePageRasterPdf(pdf_page.get(), print_settings); + if (!temp_doc) + return nullptr; + + if (!FPDF_ImportPages(rasterized_doc.get(), temp_doc.get(), "1", i)) + return nullptr; } - return buffer; + return rasterized_doc; } -FPDF_DOCUMENT PDFiumPrint::CreateSinglePageRasterPdf( - double source_page_width, - double source_page_height, - const PP_PrintSettings_Dev& print_settings, - PDFiumPage* page_to_print) { - FPDF_DOCUMENT temp_doc = FPDF_CreateNewDocument(); +ScopedFPDFDocument PDFiumPrint::CreateSinglePageRasterPdf( + FPDF_PAGE page_to_print, + const PP_PrintSettings_Dev& print_settings) { + ScopedFPDFDocument temp_doc(FPDF_CreateNewDocument()); DCHECK(temp_doc); - const pp::Size& bitmap_size(page_to_print->rect().size()); + double source_page_width = FPDF_GetPageWidth(page_to_print); + double source_page_height = FPDF_GetPageHeight(page_to_print); - pp::ImageData image = - pp::ImageData(engine_->GetPluginInstance(), - PP_IMAGEDATAFORMAT_BGRA_PREMUL, bitmap_size, false); + // For computing size in pixels, use a square dpi since the source PDF page + // has square DPI. + int width_in_pixels = + ConvertUnit(source_page_width, kPointsPerInch, print_settings.dpi); + int height_in_pixels = + ConvertUnit(source_page_height, kPointsPerInch, print_settings.dpi); - ScopedFPDFBitmap bitmap( - FPDFBitmap_CreateEx(bitmap_size.width(), bitmap_size.height(), - FPDFBitmap_BGRx, image.data(), image.stride())); + pp::Size bitmap_size(width_in_pixels, height_in_pixels); + ScopedFPDFBitmap bitmap(FPDFBitmap_Create( + bitmap_size.width(), bitmap_size.height(), /*alpha=*/false)); // Clear the bitmap FPDFBitmap_FillRect(bitmap.get(), 0, 0, bitmap_size.width(), bitmap_size.height(), 0xFFFFFFFF); - pp::Rect page_rect = page_to_print->rect(); - FPDF_RenderPageBitmap(bitmap.get(), page_to_print->GetPrintPage(), - page_rect.x(), page_rect.y(), page_rect.width(), - page_rect.height(), print_settings.orientation, + FPDF_RenderPageBitmap(bitmap.get(), page_to_print, 0, 0, bitmap_size.width(), + bitmap_size.height(), print_settings.orientation, FPDF_PRINTING | FPDF_NO_CATCH); - // Draw the forms. - FPDF_FFLDraw(engine_->form(), bitmap.get(), page_to_print->GetPrintPage(), - page_rect.x(), page_rect.y(), page_rect.width(), - page_rect.height(), print_settings.orientation, - FPDF_ANNOT | FPDF_PRINTING | FPDF_NO_CATCH); - unsigned char* bitmap_data = static_cast<unsigned char*>(FPDFBitmap_GetBuffer(bitmap.get())); double ratio_x = ConvertUnitDouble(bitmap_size.width(), print_settings.dpi, @@ -376,7 +424,7 @@ FPDF_DOCUMENT PDFiumPrint::CreateSinglePageRasterPdf( // Add the bitmap to an image object and add the image object to the output // page. - FPDF_PAGEOBJECT temp_img = FPDFPageObj_NewImageObj(temp_doc); + FPDF_PAGEOBJECT temp_img = FPDFPageObj_NewImageObj(temp_doc.get()); bool encoded = false; std::vector<uint8_t> compressed_bitmap_data; @@ -384,7 +432,7 @@ FPDF_DOCUMENT PDFiumPrint::CreateSinglePageRasterPdf( // Use quality = 40 as this does not significantly degrade the printed // document relative to a normal bitmap and provides better compression than // a higher quality setting. - const int kQuality = 40; + constexpr int kQuality = 40; SkImageInfo info = SkImageInfo::Make( FPDFBitmap_GetWidth(bitmap.get()), FPDFBitmap_GetHeight(bitmap.get()), kBGRA_8888_SkColorType, kOpaque_SkAlphaType); @@ -394,7 +442,7 @@ FPDF_DOCUMENT PDFiumPrint::CreateSinglePageRasterPdf( { ScopedFPDFPage temp_page_holder( - FPDFPage_New(temp_doc, 0, source_page_width, source_page_height)); + FPDFPage_New(temp_doc.get(), 0, source_page_width, source_page_height)); FPDF_PAGE temp_page = temp_page_holder.get(); if (encoded) { FPDF_FILEACCESS file_access = {}; @@ -413,40 +461,10 @@ FPDF_DOCUMENT PDFiumPrint::CreateSinglePageRasterPdf( FPDFPage_GenerateContent(temp_page); } - page_to_print->ClosePrintPage(); return temp_doc; } -pp::Buffer_Dev PDFiumPrint::NupPdfToPdf( - FPDF_DOCUMENT doc, - uint32_t pages_per_sheet, - const PP_PrintSettings_Dev& print_settings) { - DCHECK(doc); - DCHECK(ShouldDoNup(pages_per_sheet)); - - PP_Size page_size = print_settings.paper_size; - - printing::NupParameters nup_params; - bool is_landscape = IsSourcePdfLandscape(doc); - nup_params.SetParameters(pages_per_sheet, is_landscape); - - // Import n pages to one. - bool paper_is_landscape = page_size.width > page_size.height; - if (nup_params.landscape() != paper_is_landscape) - std::swap(page_size.width, page_size.height); - - ScopedFPDFDocument output_doc_nup(FPDF_ImportNPagesToOne( - doc, page_size.width, page_size.height, nup_params.num_pages_on_x_axis(), - nup_params.num_pages_on_y_axis())); - if (!output_doc_nup) - return pp::Buffer_Dev(); - - FitContentsToPrintableAreaIfRequired(output_doc_nup.get(), 1.0f, - print_settings); - return GetPrintData(output_doc_nup.get()); -} - -bool PDFiumPrint::FlattenPrintData(FPDF_DOCUMENT doc) { +bool PDFiumPrint::FlattenPrintData(FPDF_DOCUMENT doc) const { DCHECK(doc); ScopedSubstFont scoped_subst_font(engine_); @@ -460,27 +478,4 @@ bool PDFiumPrint::FlattenPrintData(FPDF_DOCUMENT doc) { return true; } -pp::Buffer_Dev PDFiumPrint::GetPrintData(FPDF_DOCUMENT doc) { - DCHECK(doc); - - pp::Buffer_Dev buffer; - PDFiumMemBufferFileWrite output_file_write; - if (FPDF_SaveAsCopy(doc, &output_file_write, 0)) { - size_t size = output_file_write.size(); - buffer = pp::Buffer_Dev(engine_->GetPluginInstance(), size); - if (!buffer.is_null()) - memcpy(buffer.data(), output_file_write.buffer().data(), size); - } - return buffer; -} - -pp::Buffer_Dev PDFiumPrint::GetFlattenedPrintData(FPDF_DOCUMENT doc) { - DCHECK(doc); - - pp::Buffer_Dev buffer; - if (FlattenPrintData(doc)) - buffer = GetPrintData(doc); - return buffer; -} - } // namespace chrome_pdf diff --git a/chromium/pdf/pdfium/pdfium_print.h b/chromium/pdf/pdfium/pdfium_print.h index 5405a1fc282..e76c5938f26 100644 --- a/chromium/pdf/pdfium/pdfium_print.h +++ b/chromium/pdf/pdfium/pdfium_print.h @@ -8,17 +8,21 @@ #include <vector> #include "base/macros.h" -#include "ppapi/cpp/dev/buffer_dev.h" +#include "third_party/pdfium/public/cpp/fpdf_scopers.h" #include "third_party/pdfium/public/fpdfview.h" struct PP_PdfPrintSettings_Dev; struct PP_PrintSettings_Dev; struct PP_PrintPageNumberRange_Dev; +namespace gfx { +class Rect; +class Size; +} // namespace gfx + namespace chrome_pdf { class PDFiumEngine; -class PDFiumPage; class PDFiumPrint { public: @@ -29,16 +33,14 @@ class PDFiumPrint { const PP_PrintPageNumberRange_Dev* page_ranges, uint32_t page_range_count); - pp::Buffer_Dev PrintPagesAsRasterPDF( - const PP_PrintPageNumberRange_Dev* page_ranges, - uint32_t page_range_count, - const PP_PrintSettings_Dev& print_settings, - const PP_PdfPrintSettings_Dev& pdf_print_settings); - pp::Buffer_Dev PrintPagesAsPDF( - const PP_PrintPageNumberRange_Dev* page_ranges, - uint32_t page_range_count, - const PP_PrintSettings_Dev& print_settings, - const PP_PdfPrintSettings_Dev& pdf_print_settings); + // Performs N-up PDF generation for |doc| based on |pages_per_sheet|, + // |page_size|, and |printable_area|. + // On success, returns the N-up version of |doc| as a vector. + // On failure, returns an empty vector. + static std::vector<uint8_t> CreateNupPdf(ScopedFPDFDocument doc, + size_t pages_per_sheet, + const gfx::Size& page_size, + const gfx::Rect& printable_area); // Check the source doc orientation. Returns true if the doc is landscape. // For now the orientation of the doc is determined by its first page's @@ -49,24 +51,33 @@ class PDFiumPrint { // will not be rotated. static bool IsSourcePdfLandscape(FPDF_DOCUMENT doc); + static void FitContentsToPrintableArea(FPDF_DOCUMENT doc, + const gfx::Size& page_size, + const gfx::Rect& printable_area); + + std::vector<uint8_t> PrintPagesAsPdf( + const PP_PrintPageNumberRange_Dev* page_ranges, + uint32_t page_range_count, + const PP_PrintSettings_Dev& print_settings, + const PP_PdfPrintSettings_Dev& pdf_print_settings, + bool raster); + private: - FPDF_DOCUMENT CreateSinglePageRasterPdf( - double source_page_width, - double source_page_height, + ScopedFPDFDocument CreatePrintPdf( + const PP_PrintPageNumberRange_Dev* page_ranges, + uint32_t page_range_count, const PP_PrintSettings_Dev& print_settings, - PDFiumPage* page_to_print); - - // Perform N-up PDF generation from |doc| based on |pages_per_sheet| and - // the parameters in |print_settings|. - // On success, the returned buffer contains the N-up version of |doc|. - // On failure, the returned buffer is empty. - pp::Buffer_Dev NupPdfToPdf(FPDF_DOCUMENT doc, - uint32_t pages_per_sheet, - const PP_PrintSettings_Dev& print_settings); - - bool FlattenPrintData(FPDF_DOCUMENT doc); - pp::Buffer_Dev GetPrintData(FPDF_DOCUMENT doc); - pp::Buffer_Dev GetFlattenedPrintData(FPDF_DOCUMENT doc); + const PP_PdfPrintSettings_Dev& pdf_print_settings); + + ScopedFPDFDocument CreateRasterPdf( + ScopedFPDFDocument doc, + const PP_PrintSettings_Dev& print_settings); + + ScopedFPDFDocument CreateSinglePageRasterPdf( + FPDF_PAGE page_to_print, + const PP_PrintSettings_Dev& print_settings); + + bool FlattenPrintData(FPDF_DOCUMENT doc) const; PDFiumEngine* const engine_; diff --git a/chromium/pdf/pdfium/pdfium_print_unittest.cc b/chromium/pdf/pdfium/pdfium_print_unittest.cc new file mode 100644 index 00000000000..57663c10c72 --- /dev/null +++ b/chromium/pdf/pdfium/pdfium_print_unittest.cc @@ -0,0 +1,137 @@ +// Copyright 2018 The Chromium 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 "pdf/pdfium/pdfium_print.h" + +#include <memory> + +#include "base/stl_util.h" +#include "pdf/pdfium/pdfium_engine.h" +#include "pdf/pdfium/pdfium_engine_exports.h" +#include "pdf/pdfium/pdfium_test_base.h" +#include "pdf/test/test_client.h" +#include "ppapi/c/dev/ppp_printing_dev.h" +#include "ppapi/c/private/ppp_pdf.h" +#include "testing/gmock/include/gmock/gmock.h" + +namespace chrome_pdf { + +using PDFiumPrintTest = PDFiumTestBase; +using testing::ElementsAre; + +namespace { + +constexpr PP_Size kUSLetterSize = {612, 792}; +constexpr PP_Rect kUSLetterRect = {{0, 0}, kUSLetterSize}; + +struct SizeDouble { + double width; + double height; +}; + +using ExpectedDimensions = std::vector<SizeDouble>; + +void CheckPdfDimensions(const std::vector<uint8_t>& pdf_data, + const ExpectedDimensions& expected_dimensions) { + PDFiumEngineExports exports; + int page_count; + ASSERT_TRUE(exports.GetPDFDocInfo(pdf_data, &page_count, nullptr)); + ASSERT_GT(page_count, 0); + ASSERT_EQ(expected_dimensions.size(), static_cast<size_t>(page_count)); + + for (int i = 0; i < page_count; ++i) { + double width; + double height; + ASSERT_TRUE(exports.GetPDFPageSizeByIndex(pdf_data, i, &width, &height)); + EXPECT_DOUBLE_EQ(expected_dimensions[i].width, width); + EXPECT_DOUBLE_EQ(expected_dimensions[i].height, height); + } +} + +} // namespace + +TEST_F(PDFiumPrintTest, GetPageNumbersFromPrintPageNumberRange) { + std::vector<uint32_t> page_numbers; + + { + const PP_PrintPageNumberRange_Dev page_ranges[] = {{0, 2}}; + page_numbers = PDFiumPrint::GetPageNumbersFromPrintPageNumberRange( + &page_ranges[0], base::size(page_ranges)); + EXPECT_THAT(page_numbers, ElementsAre(0, 1, 2)); + } + { + const PP_PrintPageNumberRange_Dev page_ranges[] = {{0, 0}, {2, 2}, {4, 5}}; + page_numbers = PDFiumPrint::GetPageNumbersFromPrintPageNumberRange( + &page_ranges[0], base::size(page_ranges)); + EXPECT_THAT(page_numbers, ElementsAre(0, 2, 4, 5)); + } +} + +TEST_F(PDFiumPrintTest, Basic) { + TestClient client; + std::unique_ptr<PDFiumEngine> engine = + InitializeEngine(&client, FILE_PATH_LITERAL("hello_world2.pdf")); + ASSERT_TRUE(engine); + + PDFiumPrint print(engine.get()); + + constexpr PP_PrintSettings_Dev print_settings = {kUSLetterRect, + kUSLetterRect, + kUSLetterSize, + 72, + PP_PRINTORIENTATION_NORMAL, + PP_PRINTSCALINGOPTION_NONE, + PP_FALSE, + PP_PRINTOUTPUTFORMAT_PDF}; + constexpr PP_PdfPrintSettings_Dev pdf_print_settings = {1, 100}; + + { + // Print 2 pages. + const ExpectedDimensions kExpectedDimensions = {{612.0, 792.0}, + {612.0, 792.0}}; + const PP_PrintPageNumberRange_Dev page_ranges[] = {{0, 1}}; + std::vector<uint8_t> pdf_data = + print.PrintPagesAsPdf(&page_ranges[0], base::size(page_ranges), + print_settings, pdf_print_settings, + /*raster=*/false); + CheckPdfDimensions(pdf_data, kExpectedDimensions); + + pdf_data = print.PrintPagesAsPdf(&page_ranges[0], base::size(page_ranges), + print_settings, pdf_print_settings, + /*raster=*/true); + CheckPdfDimensions(pdf_data, kExpectedDimensions); + } + { + // Print 1 page. + const ExpectedDimensions kExpectedDimensions = {{612.0, 792.0}}; + const PP_PrintPageNumberRange_Dev page_ranges[] = {{0, 0}}; + std::vector<uint8_t> pdf_data = + print.PrintPagesAsPdf(&page_ranges[0], base::size(page_ranges), + print_settings, pdf_print_settings, + /*raster=*/false); + CheckPdfDimensions(pdf_data, kExpectedDimensions); + + pdf_data = print.PrintPagesAsPdf(&page_ranges[0], base::size(page_ranges), + print_settings, pdf_print_settings, + /*raster=*/true); + CheckPdfDimensions(pdf_data, kExpectedDimensions); + } + { + // Print the other page. + const ExpectedDimensions kExpectedDimensions = {{612.0, 792.0}}; + const PP_PrintPageNumberRange_Dev page_ranges[] = {{1, 1}}; + std::vector<uint8_t> pdf_data = + print.PrintPagesAsPdf(&page_ranges[0], base::size(page_ranges), + print_settings, pdf_print_settings, + /*raster=*/false); + CheckPdfDimensions(pdf_data, kExpectedDimensions); + + pdf_data = print.PrintPagesAsPdf(&page_ranges[0], base::size(page_ranges), + print_settings, pdf_print_settings, + /*raster=*/true); + CheckPdfDimensions(pdf_data, kExpectedDimensions); + } +} + +} // namespace chrome_pdf diff --git a/chromium/pdf/pdfium/pdfium_range.cc b/chromium/pdf/pdfium/pdfium_range.cc index bec834ff3d9..a89c428bf1c 100644 --- a/chromium/pdf/pdfium/pdfium_range.cc +++ b/chromium/pdf/pdfium/pdfium_range.cc @@ -23,6 +23,10 @@ void AdjustForBackwardsRange(int* index, int* count) { } // namespace +bool IsIgnorableCharacter(base::char16 c) { + return (c == kZeroWidthSpace) || (c == kPDFSoftHyphenMarker); +} + PDFiumRange::PDFiumRange(PDFiumPage* page, int char_index, int char_count) : page_(page), char_index_(char_index), char_count_(char_count) { #if DCHECK_IS_ON() @@ -105,6 +109,8 @@ base::string16 PDFiumRange::GetText() const { api_string_adapter.Close(written); } + base::EraseIf(rv, [](base::char16 c) { return IsIgnorableCharacter(c); }); + return rv; } diff --git a/chromium/pdf/pdfium/pdfium_range.h b/chromium/pdf/pdfium/pdfium_range.h index 56b0fcadb8e..80ab37e430c 100644 --- a/chromium/pdf/pdfium/pdfium_range.h +++ b/chromium/pdf/pdfium/pdfium_range.h @@ -14,6 +14,14 @@ namespace chrome_pdf { +constexpr base::char16 kZeroWidthSpace = 0x200B; +constexpr base::char16 kPDFSoftHyphenMarker = 0xFFFE; + +// Helper for identifying characters that PDFium outputs, via FPDFText_GetText, +// that have special meaning, but should not be included in things like copied +// text or when running find. +bool IsIgnorableCharacter(base::char16 c); + // Describes location of a string of characters. class PDFiumRange { public: diff --git a/chromium/pdf/pdfium/pdfium_test_base.cc b/chromium/pdf/pdfium/pdfium_test_base.cc new file mode 100644 index 00000000000..4acdcdddc1c --- /dev/null +++ b/chromium/pdf/pdfium/pdfium_test_base.cc @@ -0,0 +1,70 @@ +// Copyright 2018 The Chromium 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 "pdf/pdfium/pdfium_test_base.h" + +#include <memory> + +#include "pdf/pdfium/pdfium_engine.h" +#include "pdf/test/test_client.h" +#include "pdf/test/test_document_loader.h" + +namespace chrome_pdf { + +namespace { + +const base::FilePath::CharType* g_test_pdf_name; + +std::unique_ptr<DocumentLoader> CreateTestDocumentLoader( + DocumentLoader::Client* client) { + return std::make_unique<TestDocumentLoader>(client, g_test_pdf_name); +} + +} // namespace + +PDFiumTestBase::PDFiumTestBase() = default; + +PDFiumTestBase::~PDFiumTestBase() = default; + +void PDFiumTestBase::SetUp() { + InitializePDFium(); +} + +void PDFiumTestBase::TearDown() { + PDFiumEngine::SetCreateDocumentLoaderFunctionForTesting(nullptr); + g_test_pdf_name = nullptr; + FPDF_DestroyLibrary(); +} + +std::unique_ptr<PDFiumEngine> PDFiumTestBase::InitializeEngine( + TestClient* client, + const base::FilePath::CharType* pdf_name) { + SetDocumentForTest(pdf_name); + pp::URLLoader dummy_loader; + auto engine = std::make_unique<PDFiumEngine>(client, true); + if (!engine->New("https://chromium.org/dummy.pdf", "") || + !engine->HandleDocumentLoad(dummy_loader)) { + return nullptr; + } + return engine; +} + +void PDFiumTestBase::SetDocumentForTest( + const base::FilePath::CharType* pdf_name) { + DCHECK(!g_test_pdf_name); + g_test_pdf_name = pdf_name; + PDFiumEngine::SetCreateDocumentLoaderFunctionForTesting( + &CreateTestDocumentLoader); +} + +void PDFiumTestBase::InitializePDFium() { + FPDF_LIBRARY_CONFIG config; + config.version = 2; + config.m_pUserFontPaths = nullptr; + config.m_pIsolate = nullptr; + config.m_v8EmbedderSlot = 0; + FPDF_InitLibraryWithConfig(&config); +} + +} // namespace chrome_pdf diff --git a/chromium/pdf/pdfium/pdfium_test_base.h b/chromium/pdf/pdfium/pdfium_test_base.h new file mode 100644 index 00000000000..d7956f26d64 --- /dev/null +++ b/chromium/pdf/pdfium/pdfium_test_base.h @@ -0,0 +1,47 @@ +// Copyright 2018 The Chromium 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 PDF_PDFIUM_PDFIUM_TEST_BASE_H_ +#define PDF_PDFIUM_PDFIUM_TEST_BASE_H_ + +#include <memory> + +#include "base/files/file_path.h" +#include "base/macros.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace chrome_pdf { + +class PDFiumEngine; +class TestClient; + +class PDFiumTestBase : public testing::Test { + public: + PDFiumTestBase(); + ~PDFiumTestBase() override; + + protected: + // testing::Test: + void SetUp() override; + void TearDown() override; + + // Initializes a PDFiumEngine for use in testing with |client|. Loads a PDF + // named |pdf_name|.See TestDocumentLoader for more info about |pdf_name|. + std::unique_ptr<PDFiumEngine> InitializeEngine( + TestClient* client, + const base::FilePath::CharType* pdf_name); + + private: + // Sets the PDF to load for a test. This must be called for tests that use + // TestDocumentLoader. See TestDocumentLoader for more info. + void SetDocumentForTest(const base::FilePath::CharType* pdf_name); + + void InitializePDFium(); + + DISALLOW_COPY_AND_ASSIGN(PDFiumTestBase); +}; + +} // namespace chrome_pdf + +#endif // PDF_PDFIUM_PDFIUM_TEST_BASE_H_ |