From 03c549e0392f92c02536d3f86d5e1d8dfa3435ac Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Wed, 1 Sep 2021 11:08:40 +0200 Subject: BASELINE: Update Chromium to 91.0.4472.160 Change-Id: I0def1f08a2412aeed79a9ab95dd50eb5c3f65f31 Reviewed-by: Allan Sandfeld Jensen --- chromium/pdf/BUILD.gn | 43 +- chromium/pdf/DEPS | 16 +- chromium/pdf/content_restriction.h | 26 + chromium/pdf/document_attachment_info.h | 9 +- chromium/pdf/features.gni | 8 + chromium/pdf/out_of_process_instance.cc | 801 ++------------------- chromium/pdf/out_of_process_instance.h | 145 +--- chromium/pdf/out_of_process_instance_unittest.cc | 36 - chromium/pdf/paint_manager.cc | 5 +- chromium/pdf/paint_manager.h | 18 +- chromium/pdf/pdf_engine.h | 35 +- chromium/pdf/pdf_view_plugin_base.cc | 635 ++++++++++++++-- chromium/pdf/pdf_view_plugin_base.h | 163 ++++- chromium/pdf/pdf_view_plugin_base_unittest.cc | 161 +++++ chromium/pdf/pdf_view_web_plugin.cc | 175 +++-- chromium/pdf/pdf_view_web_plugin.h | 75 +- chromium/pdf/pdfium/DEPS | 7 +- chromium/pdf/pdfium/findtext_unittest.cc | 12 +- .../pdf/pdfium/pdfium_api_string_buffer_adapter.cc | 12 +- .../pdf/pdfium/pdfium_api_string_buffer_adapter.h | 21 +- .../pdf/pdfium/pdfium_assert_matching_enums.cc | 12 + chromium/pdf/pdfium/pdfium_engine.cc | 128 ++-- chromium/pdf/pdfium/pdfium_engine.h | 8 +- chromium/pdf/pdfium/pdfium_engine_exports.cc | 6 +- chromium/pdf/pdfium/pdfium_engine_unittest.cc | 2 +- chromium/pdf/pdfium/pdfium_form_filler.cc | 7 +- chromium/pdf/pdfium/pdfium_page.cc | 29 +- chromium/pdf/pdfium/pdfium_page.h | 10 +- chromium/pdf/pdfium/pdfium_page_unittest.cc | 2 +- chromium/pdf/pdfium/pdfium_range.cc | 10 +- chromium/pdf/pdfium/pdfium_range.h | 9 +- chromium/pdf/post_message_receiver.cc | 14 +- chromium/pdf/post_message_sender.cc | 1 + .../pdf/ppapi_migration/geometry_conversions.cc | 5 - .../pdf/ppapi_migration/geometry_conversions.h | 1 - .../geometry_conversions_unittest.cc | 10 - chromium/pdf/ppapi_migration/graphics.cc | 30 +- chromium/pdf/ppapi_migration/graphics.h | 26 +- chromium/pdf/ppapi_migration/graphics_unittest.cc | 193 ++++- .../pdf/ppapi_migration/input_event_conversions.cc | 17 + .../pdf/ppapi_migration/input_event_conversions.h | 4 + chromium/pdf/preview_mode_client.cc | 14 +- chromium/pdf/preview_mode_client.h | 23 +- chromium/pdf/thumbnail.cc | 125 ---- chromium/pdf/thumbnail.h | 41 -- chromium/pdf/thumbnail_unittest.cc | 83 --- chromium/pdf/ui/DEPS | 2 +- chromium/pdf/ui/README.md | 4 - chromium/pdf/ui/document_properties.cc | 122 ++++ chromium/pdf/ui/document_properties.h | 35 + chromium/pdf/ui/document_properties_unittest.cc | 167 +++++ chromium/pdf/ui/file_name.cc | 25 + chromium/pdf/ui/file_name.h | 17 + chromium/pdf/ui/file_name_unittest.cc | 32 + chromium/pdf/ui/format_page_size.cc | 93 --- chromium/pdf/ui/format_page_size.h | 29 - chromium/pdf/ui/format_page_size_unittest.cc | 163 ----- chromium/pdf/ui/thumbnail.cc | 125 ++++ chromium/pdf/ui/thumbnail.h | 41 ++ chromium/pdf/ui/thumbnail_unittest.cc | 83 +++ chromium/pdf/url_loader_wrapper_impl.cc | 1 + 61 files changed, 2241 insertions(+), 1911 deletions(-) create mode 100644 chromium/pdf/content_restriction.h delete mode 100644 chromium/pdf/out_of_process_instance_unittest.cc create mode 100644 chromium/pdf/pdf_view_plugin_base_unittest.cc delete mode 100644 chromium/pdf/thumbnail.cc delete mode 100644 chromium/pdf/thumbnail.h delete mode 100644 chromium/pdf/thumbnail_unittest.cc create mode 100644 chromium/pdf/ui/document_properties.cc create mode 100644 chromium/pdf/ui/document_properties.h create mode 100644 chromium/pdf/ui/document_properties_unittest.cc create mode 100644 chromium/pdf/ui/file_name.cc create mode 100644 chromium/pdf/ui/file_name.h create mode 100644 chromium/pdf/ui/file_name_unittest.cc delete mode 100644 chromium/pdf/ui/format_page_size.cc delete mode 100644 chromium/pdf/ui/format_page_size.h delete mode 100644 chromium/pdf/ui/format_page_size_unittest.cc create mode 100644 chromium/pdf/ui/thumbnail.cc create mode 100644 chromium/pdf/ui/thumbnail.h create mode 100644 chromium/pdf/ui/thumbnail_unittest.cc (limited to 'chromium/pdf') diff --git a/chromium/pdf/BUILD.gn b/chromium/pdf/BUILD.gn index 3bc34164cde..aa5cb6e45a4 100644 --- a/chromium/pdf/BUILD.gn +++ b/chromium/pdf/BUILD.gn @@ -13,7 +13,10 @@ import("//v8/gni/v8.gni") # Generate a buildflag header for compile-time checking of PDF support. buildflag_header("buildflags") { header = "buildflags.h" - flags = [ "ENABLE_PDF=$enable_pdf" ] + flags = [ + "ENABLE_PDF=$enable_pdf", + "ENABLE_PDF_UNSEASONED=$enable_pdf_unseasoned", + ] } if (enable_pdf) { @@ -49,7 +52,6 @@ if (enable_pdf) { ":internal", ":out_of_process_instance", ":pdf", - ":pdf_view_web_plugin", "//base", "//ppapi/cpp:objects", "//ppapi/cpp/private:internal_module", @@ -78,6 +80,7 @@ if (enable_pdf) { "accessibility.cc", "accessibility.h", "chunk_stream.h", + "content_restriction.h", "document_attachment_info.cc", "document_attachment_info.h", "document_layout.cc", @@ -136,10 +139,12 @@ if (enable_pdf) { "preview_mode_client.h", "range_set.cc", "range_set.h", - "thumbnail.cc", - "thumbnail.h", - "ui/format_page_size.cc", - "ui/format_page_size.h", + "ui/document_properties.cc", + "ui/document_properties.h", + "ui/file_name.cc", + "ui/file_name.h", + "ui/thumbnail.cc", + "ui/thumbnail.h", "url_loader_wrapper.h", "url_loader_wrapper_impl.cc", "url_loader_wrapper_impl.h", @@ -166,6 +171,8 @@ if (enable_pdf) { "//third_party/icu", "//third_party/pdfium", "//ui/base", + "//ui/base/cursor/mojom:cursor_type", + "//ui/gfx/codec", "//ui/gfx/range", ] @@ -245,6 +252,8 @@ if (enable_pdf) { "//skia", "//third_party/blink/public:blink", "//ui/base", + "//ui/base/cursor/mojom:cursor_type", + "//ui/gfx", ] } @@ -272,16 +281,19 @@ if (enable_pdf) { "//ppapi/cpp/private:internal_module", "//skia", "//ui/base", + "//ui/base/cursor/mojom:cursor_type", ] } # Eventual replacement for out_of_process_instance. - source_set("pdf_view_web_plugin") { - visibility = [ ":*" ] + static_library("pdf_view_web_plugin") { + visibility = [ + ":*", + "//chrome/renderer", + ] sources = [ "pdf_view_web_plugin.cc", - "pdf_view_web_plugin.h", "post_message_receiver.cc", "post_message_receiver.h", "post_message_sender.cc", @@ -290,6 +302,8 @@ if (enable_pdf) { configs += [ ":pdf_common_config" ] + public = [ "pdf_view_web_plugin.h" ] + deps = [ ":accessibility_structs", ":internal", @@ -302,6 +316,7 @@ if (enable_pdf) { "//skia", "//third_party/blink/public:blink_headers", "//ui/base/cursor:cursor_base", + "//ui/base/cursor/mojom:cursor_type", "//v8", ] } @@ -338,10 +353,10 @@ if (enable_pdf) { "document_layout_unittest.cc", "document_loader_impl_unittest.cc", "draw_utils/coordinates_unittest.cc", - "out_of_process_instance_unittest.cc", "page_orientation_unittest.cc", "pdf_transform_unittest.cc", "pdf_utils/dates_unittest.cc", + "pdf_view_plugin_base_unittest.cc", "pdfium/accessibility_unittest.cc", "pdfium/findtext_unittest.cc", "pdfium/pdfium_engine_exports_unittest.cc", @@ -357,8 +372,9 @@ if (enable_pdf) { "ppapi_migration/url_loader_unittest.cc", "range_set_unittest.cc", "test/run_all_unittests.cc", - "thumbnail_unittest.cc", - "ui/format_page_size_unittest.cc", + "ui/document_properties_unittest.cc", + "ui/file_name_unittest.cc", + "ui/thumbnail_unittest.cc", ] configs += [ @@ -376,6 +392,7 @@ if (enable_pdf) { ":out_of_process_instance", ":pdf", ":pdf_test_utils", + ":pdf_view_web_plugin", ":ppapi_migration", "//base", "//base:i18n", @@ -419,4 +436,6 @@ if (enable_pdf) { } group("pdf_ppapi") { } + group("pdf_view_web_plugin") { + } } diff --git a/chromium/pdf/DEPS b/chromium/pdf/DEPS index 27b4a84dab1..184bbb1bb23 100644 --- a/chromium/pdf/DEPS +++ b/chromium/pdf/DEPS @@ -1,23 +1,15 @@ include_rules = [ "+cc/paint", "+content/public/renderer/v8_value_converter.h", - "+gin/handle.h", - "+gin/public", - "+gin/object_template_builder.h", - "+gin/wrappable.h", + "+gin", "+net", "+ppapi", - "+printing/units.h", + "+printing", "+third_party/blink/public", "+third_party/skia/include/core", - "+ui/base/cursor/cursor.h", - "+ui/base/text/bytes_formatting.h", - "+ui/base/window_open_disposition.h", + "+ui/base", "+ui/events/keycodes/keyboard_codes.h", - "+ui/gfx/geometry", - "+ui/gfx/range/range.h", - "+ui/gfx/skia_util.h", - "+ui/gfx/test/gfx_util.h", + "+ui/gfx", "+v8/include/v8.h" ] diff --git a/chromium/pdf/content_restriction.h b/chromium/pdf/content_restriction.h new file mode 100644 index 00000000000..f42be8cb8d3 --- /dev/null +++ b/chromium/pdf/content_restriction.h @@ -0,0 +1,26 @@ +// Copyright 2021 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_CONTENT_RESTRICTION_H_ +#define PDF_CONTENT_RESTRICTION_H_ + +namespace chrome_pdf { + +// Used for disabling browser commands because of restrictions on how the data +// is to be used (i.e. can't copy/print). +// TODO(crbug.com/702993): Must be kept in sync with `ContentRestriction` in +// chrome/common/content_restriction.h. While there's a transitive static +// assertion that the enums match, a direct static assertion should be added +// when `PP_ContentRestriction` is removed. +enum ContentRestriction { + kContentRestrictionCopy = 1 << 0, + kContentRestrictionCut = 1 << 1, + kContentRestrictionPaste = 1 << 2, + kContentRestrictionPrint = 1 << 3, + kContentRestrictionSave = 1 << 4 +}; + +} // namespace chrome_pdf + +#endif // PDF_CONTENT_RESTRICTION_H_ diff --git a/chromium/pdf/document_attachment_info.h b/chromium/pdf/document_attachment_info.h index 254398e6226..138ca2efec4 100644 --- a/chromium/pdf/document_attachment_info.h +++ b/chromium/pdf/document_attachment_info.h @@ -5,7 +5,8 @@ #ifndef PDF_DOCUMENT_ATTACHMENT_INFO_H_ #define PDF_DOCUMENT_ATTACHMENT_INFO_H_ -#include "base/strings/string16.h" +#include + namespace chrome_pdf { @@ -17,18 +18,18 @@ struct DocumentAttachmentInfo { ~DocumentAttachmentInfo(); // The attachment's name. - base::string16 name; + std::u16string name; // The attachment's size in bytes. uint32_t size_bytes = 0; // The creation date of the attachment. It stores the arbitrary string saved // in field "CreationDate". - base::string16 creation_date; + std::u16string creation_date; // Last modified date of the attachment. It stores the arbitrary string saved // in field "ModDate". - base::string16 modified_date; + std::u16string modified_date; // The flag that indicates whether the attachment can be retrieved // successfully. diff --git a/chromium/pdf/features.gni b/chromium/pdf/features.gni index aea81fba7d2..8b7c8138465 100644 --- a/chromium/pdf/features.gni +++ b/chromium/pdf/features.gni @@ -10,4 +10,12 @@ import("//build/config/chromecast_build.gni") declare_args() { enable_pdf = !is_android && !is_ios && !is_chromecast + + # Enable additional code for the Pepper-free PDF viewer. + # + # This argument enables additional code paths that are only useful during the + # PDF viewer's migration from Pepper. This argument is intended to guard code + # meant only for developers, and will be phased out before launch in favor of + # a run-time feature flag. + enable_pdf_unseasoned = false } diff --git a/chromium/pdf/out_of_process_instance.cc b/chromium/pdf/out_of_process_instance.cc index 8e619bae051..4153bd63bc9 100644 --- a/chromium/pdf/out_of_process_instance.cc +++ b/chromium/pdf/out_of_process_instance.cc @@ -8,35 +8,28 @@ #include #include -#include // for min/max() -#include // for log() and pow() +#include #include #include #include #include "base/bind.h" #include "base/callback.h" -#include "base/i18n/number_formatting.h" -#include "base/i18n/time_formatting.h" #include "base/location.h" #include "base/logging.h" #include "base/memory/weak_ptr.h" -#include "base/metrics/histogram_functions.h" #include "base/notreached.h" #include "base/optional.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_split.h" #include "base/strings/string_util.h" -#include "base/strings/utf_string_conversions.h" #include "base/time/time.h" #include "base/values.h" #include "build/chromeos_buildflags.h" #include "net/base/escape.h" -#include "net/base/filename_util.h" #include "pdf/accessibility.h" #include "pdf/accessibility_structs.h" #include "pdf/document_attachment_info.h" -#include "pdf/document_layout.h" #include "pdf/document_metadata.h" #include "pdf/pdfium/pdfium_engine.h" #include "pdf/ppapi_migration/bitmap.h" @@ -46,8 +39,6 @@ #include "pdf/ppapi_migration/input_event_conversions.h" #include "pdf/ppapi_migration/url_loader.h" #include "pdf/ppapi_migration/value_conversions.h" -#include "pdf/thumbnail.h" -#include "pdf/ui/format_page_size.h" #include "ppapi/c/dev/ppb_cursor_control_dev.h" #include "ppapi/c/pp_errors.h" #include "ppapi/c/private/ppb_pdf.h" @@ -64,19 +55,16 @@ #include "ppapi/cpp/rect.h" #include "ppapi/cpp/resource.h" #include "ppapi/cpp/size.h" -#include "ppapi/cpp/var_array.h" #include "ppapi/cpp/var_array_buffer.h" #include "ppapi/cpp/var_dictionary.h" #include "third_party/skia/include/core/SkBitmap.h" #include "third_party/skia/include/core/SkColor.h" -#include "ui/base/text/bytes_formatting.h" +#include "ui/base/cursor/mojom/cursor_type.mojom-shared.h" #include "ui/events/keycodes/keyboard_codes.h" #include "ui/gfx/geometry/point.h" #include "ui/gfx/geometry/point_f.h" #include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/size.h" -#include "ui/gfx/geometry/vector2d.h" -#include "url/gurl.h" namespace chrome_pdf { @@ -91,56 +79,6 @@ constexpr char kType[] = "type"; // Name of identifier field passed from JS to the plugin and back, to associate // Page->Plugin messages to Plugin->Page responses. constexpr char kJSMessageId[] = "messageId"; -// Beep message arguments. (Plugin -> Page). -constexpr char kJSBeepType[] = "beep"; -// UpdateScroll message arguments. (Page -> Plugin). -constexpr char kJSUpdateScrollType[] = "updateScroll"; -constexpr char kJSUpdateScrollX[] = "x"; -constexpr char kJSUpdateScrollY[] = "y"; -// Stop scrolling message (Page -> Plugin) -constexpr char kJSStopScrollingType[] = "stopScrolling"; -// Document dimension arguments (Plugin -> Page). -constexpr char kJSDocumentDimensionsType[] = "documentDimensions"; -constexpr char kJSDocumentWidth[] = "width"; -constexpr char kJSDocumentHeight[] = "height"; -constexpr char kJSLayoutOptions[] = "layoutOptions"; -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) -constexpr char kJSLoadProgressType[] = "loadProgress"; -constexpr char kJSProgressPercentage[] = "progress"; -// Document print preview loaded (Plugin -> Page) -constexpr char kJSPreviewLoadedType[] = "printPreviewLoaded"; -// Attachments (Plugin -> Page) -constexpr char kJSAttachmentsType[] = "attachments"; -constexpr char kJSAttachmentsData[] = "attachmentsData"; -// Bookmarks (Plugin -> Page) -constexpr char kJSBookmarksType[] = "bookmarks"; -constexpr char kJSBookmarksData[] = "bookmarksData"; -// Metadata (Plugin -> Page) -constexpr char kJSMetadataType[] = "metadata"; -constexpr char kJSMetadataData[] = "metadataData"; -constexpr char kJSVersion[] = "version"; -constexpr char kJSFileSize[] = "fileSize"; -constexpr char kJSLinearized[] = "linearized"; -constexpr char kJSTitle[] = "title"; -constexpr char kJSAuthor[] = "author"; -constexpr char kJSSubject[] = "subject"; -constexpr char kJSKeywords[] = "keywords"; -constexpr char kJSCreator[] = "creator"; -constexpr char kJSProducer[] = "producer"; -constexpr char kJSCreationDate[] = "creationDate"; -constexpr char kJSModDate[] = "modDate"; -constexpr char kJSPageSize[] = "pageSize"; -constexpr char kJSCanSerializeDocument[] = "canSerializeDocument"; -// Get password (Plugin -> Page) -constexpr char kJSGetPasswordType[] = "getPassword"; -// Get password complete arguments (Page -> Plugin) -constexpr char kJSGetPasswordCompleteType[] = "getPasswordComplete"; -constexpr char kJSPassword[] = "password"; // Print (Page -> Plugin) constexpr char kJSPrintType[] = "print"; // Save attachment (Page -> Plugin) @@ -153,17 +91,6 @@ constexpr char kJSAttachmentDataToSave[] = "dataToSave"; constexpr char kJSSaveType[] = "save"; constexpr char kJSToken[] = "token"; constexpr char kJSSaveRequestType[] = "saveRequestType"; -// 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"; -// Notify when touch selection occurs (Plugin -> Page) -constexpr char kJSTouchSelectionOccurredType[] = "touchSelectionOccurred"; -// Go to page (Plugin -> Page) -constexpr char kJSGoToPageType[] = "goToPage"; -constexpr char kJSPageNumber[] = "page"; // Reset print preview mode (Page -> Plugin) constexpr char kJSResetPrintPreviewModeType[] = "resetPrintPreviewMode"; constexpr char kJSPrintPreviewUrl[] = "url"; @@ -173,60 +100,13 @@ constexpr char kJSPrintPreviewPageCount[] = "pageCount"; constexpr char kJSLoadPreviewPageType[] = "loadPreviewPage"; constexpr char kJSPreviewPageUrl[] = "url"; constexpr char kJSPreviewPageIndex[] = "index"; -// Set scroll position (Plugin -> Page) -constexpr char kJSSetScrollPositionType[] = "setScrollPosition"; -constexpr char kJSPositionX[] = "x"; -constexpr char kJSPositionY[] = "y"; -// Scroll by (Plugin -> Page) -constexpr char kJSScrollByType[] = "scrollBy"; -// Navigate to the given URL (Plugin -> Page) -constexpr char kJSNavigateType[] = "navigate"; -constexpr char kJSNavigateUrl[] = "url"; -constexpr char kJSNavigateWindowOpenDisposition[] = "disposition"; -// Navigate to the given destination (Plugin -> Page) -constexpr char kJSNavigateToDestinationType[] = "navigateToDestination"; -constexpr char kJSNavigateToDestinationPage[] = "page"; -constexpr char kJSNavigateToDestinationXOffset[] = "x"; -constexpr char kJSNavigateToDestinationYOffset[] = "y"; -constexpr char kJSNavigateToDestinationZoom[] = "zoom"; -// Open the email editor with the given parameters (Plugin -> Page) -constexpr char kJSEmailType[] = "email"; -constexpr char kJSEmailTo[] = "to"; -constexpr char kJSEmailCc[] = "cc"; -constexpr char kJSEmailBcc[] = "bcc"; -constexpr char kJSEmailSubject[] = "subject"; -constexpr char kJSEmailBody[] = "body"; -// Selecting text in document (Plugin -> Page) -constexpr char kJSSetIsSelectingType[] = "setIsSelecting"; -constexpr char kJSIsSelecting[] = "isSelecting"; // Editing forms in document (Plugin -> Page) constexpr char kJSSetIsEditingType[] = "setIsEditing"; -// Notify when a form field is focused (Plugin -> Page) -constexpr char kJSFieldFocusType[] = "formFocusChange"; -constexpr char kJSFieldFocus[] = "focused"; - -// Notify when document is focused (Plugin -> Page) -constexpr char kJSDocumentFocusChangedType[] = "documentFocusChanged"; -constexpr char kJSDocumentHasFocus[] = "hasFocus"; - -// Request the thumbnail image for a particular page (Page -> Plugin) -constexpr char kJSGetThumbnailType[] = "getThumbnail"; -constexpr char kJSGetThumbnailPage[] = "page"; -// Reply with the image data of the requested thumbnail (Plugin -> Page) -constexpr char kJSGetThumbnailReplyType[] = "getThumbnailReply"; -constexpr char kJSGetThumbnailImageData[] = "imageData"; -constexpr char kJSGetThumbnailWidth[] = "width"; -constexpr char kJSGetThumbnailHeight[] = "height"; - constexpr base::TimeDelta kFindResultCooldown = base::TimeDelta::FromMilliseconds(100); -// Do not save files 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; // A different negative value to differentiate itself from |kCompletePDFIndex|. @@ -464,10 +344,6 @@ void ScalePoint(float scale, pp::Point* point) { point->set_y(static_cast(point->y() * scale)); } -bool IsSaveDataSizeValid(size_t size) { - return size > 0 && size <= kMaximumSavedFileSize; -} - PP_PrivateAccessibilityPageInfo ToPrivateAccessibilityPageInfo( const AccessibilityPageInfo& page_info) { PP_PrivateAccessibilityPageInfo pp_page_info; @@ -588,48 +464,6 @@ pp::PDF::PrivateAccessibilityPageObjects ToPrivateAccessibilityPageObjects( return pp_page_objects; } -// Converts |version| to a formatted string. -base::string16 GetFormattedVersion(PdfVersion version) { - double value = 0; - switch (version) { - case PdfVersion::k1_0: - value = 1.0; - break; - case PdfVersion::k1_1: - value = 1.1; - break; - case PdfVersion::k1_2: - value = 1.2; - break; - case PdfVersion::k1_3: - value = 1.3; - break; - case PdfVersion::k1_4: - value = 1.4; - break; - case PdfVersion::k1_5: - value = 1.5; - break; - case PdfVersion::k1_6: - value = 1.6; - break; - case PdfVersion::k1_7: - value = 1.7; - break; - case PdfVersion::k2_0: - value = 2.0; - break; - case PdfVersion::kUnknown: - case PdfVersion::k1_8: // Not an actual version - return base::string16(); - } - // The default case is excluded from the above switch statement to ensure that - // all supported versions are determinantly handled. - - DCHECK_NE(0, value); - return base::FormatDouble(value, 1); -} - } // namespace OutOfProcessInstance::OutOfProcessInstance(PP_Instance instance) @@ -671,14 +505,6 @@ bool OutOfProcessInstance::Init(uint32_t argc, CHECK(base::StartsWith(document_url_piece, kChromeExtension) || is_print_preview_); - // Check if the plugin is full frame. This is passed in from JS. - for (uint32_t i = 0; i < argc; ++i) { - if (strcmp(argn[i], "full-frame") == 0) { - full_ = true; - break; - } - } - // Allow the plugin to handle find requests. SetPluginToHandleFindRequests(); @@ -700,6 +526,8 @@ bool OutOfProcessInstance::Init(uint32_t argc, top_level_url = argv[i]; } else if (strcmp(argn[i], "headers") == 0) { headers = argv[i]; + } else if (strcmp(argn[i], "full-frame") == 0) { + set_full_frame(true); } else if (strcmp(argn[i], "background-color") == 0) { SkColor background_color; if (!base::StringToUint(argv[i], &background_color)) @@ -729,14 +557,14 @@ bool OutOfProcessInstance::Init(uint32_t argc, return true; LoadUrl(stream_url, /*is_print_preview=*/false); - url_ = original_url; + set_url(original_url); // Not all edits go through the PDF plugin's form filler. The plugin instance // can be restarted by exiting annotation mode on ChromeOS, which can set the // document to an edited state. - edit_mode_ = has_edits; + set_edit_mode(has_edits); #if !BUILDFLAG(IS_CHROMEOS_ASH) - DCHECK(!edit_mode_); + DCHECK(!edit_mode()); #endif // !BUILDFLAG(IS_CHROMEOS_ASH) pp::PDF::SetCrashData(GetPluginInstance(), original_url, top_level_url); @@ -752,11 +580,7 @@ void OutOfProcessInstance::HandleMessage(const pp::Var& message) { std::string type = dict.Get(kType).AsString(); - if (type == kJSUpdateScrollType) { - HandleUpdateScrollMessage(dict); - } else if (type == kJSGetPasswordCompleteType) { - HandleGetPasswordCompleteMessage(dict); - } else if (type == kJSPrintType) { + if (type == kJSPrintType) { Print(); } else if (type == kJSSaveAttachmentType) { HandleSaveAttachmentMessage(dict); @@ -766,10 +590,6 @@ void OutOfProcessInstance::HandleMessage(const pp::Var& message) { HandleResetPrintPreviewModeMessage(dict); } else if (type == kJSLoadPreviewPageType) { HandleLoadPreviewPageMessage(dict); - } else if (type == kJSStopScrollingType) { - set_stop_scrolling(true); - } else if (type == kJSGetThumbnailType) { - HandleGetThumbnailMessage(dict); } else { PdfViewPluginBase::HandleMessage(ValueFromVar(message)); } @@ -845,7 +665,7 @@ void OutOfProcessInstance::DidChangeView(const pp::View& view) { view.GetDeviceScale()); if (is_print_preview_ && !stop_scrolling()) { - scroll_position_ = PointFromPPPoint(view.GetScrollOffset()); + set_scroll_position(PointFromPPPoint(view.GetScrollOffset())); UpdateScroll(); } @@ -853,14 +673,6 @@ void OutOfProcessInstance::DidChangeView(const pp::View& view) { // HandleUpdateScrollMessage(). } -void OutOfProcessInstance::UpdateScroll() { - DCHECK(!stop_scrolling()); - gfx::PointF scroll_position_float(scroll_position_.x(), scroll_position_.y()); - scroll_position_float = BoundScrollPositionToDocument(scroll_position_float); - engine()->ScrolledToXPosition(scroll_position_float.x() * device_scale()); - engine()->ScrolledToYPosition(scroll_position_float.y() * device_scale()); -} - void OutOfProcessInstance::DidChangeFocus(bool has_focus) { engine()->UpdateFocus(has_focus); } @@ -1065,121 +877,18 @@ void OutOfProcessInstance::InitImageData(const gfx::Size& size) { std::make_unique(pepper_image_data_)); } -pp::VarArray OutOfProcessInstance::GetDocumentAttachments() { - const std::vector& list = - engine()->GetDocumentAttachmentInfoList(); - pp::VarArray attachments; - attachments.SetLength(list.size()); - - for (size_t i = 0; i < list.size(); ++i) { - const DocumentAttachmentInfo& attachment_info = list[i]; - pp::VarDictionary dict; - dict.Set(pp::Var("name"), pp::Var(base::UTF16ToUTF8(attachment_info.name))); - // Set |size| to -1 to indicate that the attachment is too big to be - // downloaded. - int32_t size = attachment_info.size_bytes <= kMaximumSavedFileSize - ? static_cast(attachment_info.size_bytes) - : -1; - dict.Set(pp::Var("size"), pp::Var(size)); - dict.Set(pp::Var("readable"), pp::Var(attachment_info.is_readable)); - attachments.Set(i, dict); - } - return attachments; -} - -void OutOfProcessInstance::ProposeDocumentLayout(const DocumentLayout& layout) { - pp::VarDictionary dimensions; - dimensions.Set(kType, kJSDocumentDimensionsType); - dimensions.Set(kJSDocumentWidth, pp::Var(layout.size().width())); - dimensions.Set(kJSDocumentHeight, pp::Var(layout.size().height())); - dimensions.Set(kJSLayoutOptions, VarFromValue(layout.options().ToValue())); - pp::VarArray page_dimensions_array; - for (size_t i = 0; i < layout.page_count(); ++i) { - const gfx::Rect& page_rect = layout.page_rect(i); - pp::VarDictionary page_dimensions; - page_dimensions.Set(kJSPageX, pp::Var(page_rect.x())); - page_dimensions.Set(kJSPageY, pp::Var(page_rect.y())); - page_dimensions.Set(kJSPageWidth, pp::Var(page_rect.width())); - page_dimensions.Set(kJSPageHeight, pp::Var(page_rect.height())); - page_dimensions_array.Set(i, page_dimensions); - } - dimensions.Set(kJSPageDimensions, page_dimensions_array); - PostMessage(dimensions); - - // Reload the accessibility tree on layout changes because the relative page - // bounds are no longer valid. - if (layout.dirty() && accessibility_state() == AccessibilityState::kLoaded) - LoadAccessibility(); -} - -void OutOfProcessInstance::DidScroll(const gfx::Vector2d& offset) { - if (!image_data().drawsNothing()) - paint_manager().ScrollRect(available_area(), offset); -} - -void OutOfProcessInstance::ScrollToX(int x_in_screen_coords) { - pp::VarDictionary position; - position.Set(kType, kJSSetScrollPositionType); - position.Set(kJSPositionX, pp::Var(x_in_screen_coords / device_scale())); - PostMessage(position); -} - -void OutOfProcessInstance::ScrollToY(int y_in_screen_coords) { - pp::VarDictionary position; - position.Set(kType, kJSSetScrollPositionType); - float new_y_viewport_coords = y_in_screen_coords / device_scale(); - position.Set(kJSPositionY, pp::Var(new_y_viewport_coords)); - PostMessage(position); -} - -void OutOfProcessInstance::ScrollBy(const gfx::Vector2d& scroll_delta) { - pp::VarDictionary position; - position.Set(kType, kJSScrollByType); - position.Set(kJSPositionX, pp::Var(scroll_delta.x() / device_scale())); - position.Set(kJSPositionY, pp::Var(scroll_delta.y() / device_scale())); - PostMessage(position); -} - -void OutOfProcessInstance::ScrollToPage(int page) { - if (!engine() || engine()->GetNumberOfPages() == 0) +void OutOfProcessInstance::SetFormFieldInFocus(bool in_focus) { + if (!text_input_) return; - pp::VarDictionary message; - message.Set(kType, kJSGoToPageType); - message.Set(kJSPageNumber, pp::Var(page)); - PostMessage(message); -} - -void OutOfProcessInstance::NavigateTo(const std::string& url, - WindowOpenDisposition disposition) { - pp::VarDictionary message; - message.Set(kType, kJSNavigateType); - message.Set(kJSNavigateUrl, url); - message.Set(kJSNavigateWindowOpenDisposition, - pp::Var(static_cast(disposition))); - PostMessage(message); -} - -void OutOfProcessInstance::NavigateToDestination(int page, - const float* x, - const float* y, - const float* zoom) { - pp::VarDictionary message; - message.Set(kType, kJSNavigateToDestinationType); - message.Set(kJSNavigateToDestinationPage, pp::Var(page)); - if (x) - message.Set(kJSNavigateToDestinationXOffset, pp::Var(*x)); - if (y) - message.Set(kJSNavigateToDestinationYOffset, pp::Var(*y)); - if (zoom) - message.Set(kJSNavigateToDestinationZoom, pp::Var(*zoom)); - PostMessage(message); + text_input_->SetTextInputType(in_focus ? PP_TEXTINPUT_TYPE_DEV_TEXT + : PP_TEXTINPUT_TYPE_DEV_NONE); } -void OutOfProcessInstance::UpdateCursor(PP_CursorType_Dev cursor) { - if (cursor == cursor_) +void OutOfProcessInstance::UpdateCursor(ui::mojom::CursorType cursor_type) { + if (cursor_type == cursor_type_) return; - cursor_ = cursor; + cursor_type_ = cursor_type; const PPB_CursorControl_Dev* cursor_interface = reinterpret_cast( @@ -1190,7 +899,8 @@ void OutOfProcessInstance::UpdateCursor(PP_CursorType_Dev cursor) { return; } - cursor_interface->SetCursor(pp_instance(), cursor_, + cursor_interface->SetCursor(pp_instance(), + PPCursorTypeFromCursorType(cursor_type_), pp::ImageData().pp_resource(), nullptr); } @@ -1223,10 +933,10 @@ void OutOfProcessInstance::NotifyNumberOfFindResultsChanged(int total, SetTickmarks(tickmarks_); recently_sent_find_update_ = true; ScheduleTaskOnMainThread( - kFindResultCooldown, + FROM_HERE, base::BindOnce(&OutOfProcessInstance::ResetRecentlySentFindUpdate, weak_factory_.GetWeakPtr()), - 0); + /*result=*/0, kFindResultCooldown); } void OutOfProcessInstance::NotifySelectedFindResultChanged( @@ -1235,79 +945,12 @@ void OutOfProcessInstance::NotifySelectedFindResultChanged( SelectedFindResultChanged(current_find_index); } -void OutOfProcessInstance::NotifyTouchSelectionOccurred() { - pp::VarDictionary message; - message.Set(kType, kJSTouchSelectionOccurredType); - PostMessage(message); -} - -void OutOfProcessInstance::GetDocumentPassword( - base::OnceCallback callback) { - if (password_callback_) { - NOTREACHED(); - return; - } - - password_callback_ = std::move(callback); - pp::VarDictionary message; - message.Set(kType, kJSGetPasswordType); - PostMessage(message); -} - -void OutOfProcessInstance::SaveToBuffer(const std::string& token) { - engine()->KillFormFocus(); - - pp::VarDictionary message; - message.Set(kType, kJSSaveDataType); - message.Set(kJSToken, pp::Var(token)); - message.Set(kJSFileName, pp::Var(GetFileNameFromUrl(url_))); - // This will be overwritten if the save is successful. - message.Set(kJSDataToSave, pp::Var(pp::Var::Null())); - - if (edit_mode_) { - std::vector data = engine()->GetSaveData(); - if (IsSaveDataSizeValid(data.size())) { - pp::VarArrayBuffer buffer(data.size()); - std::copy(data.begin(), data.end(), - reinterpret_cast(buffer.Map())); - message.Set(kJSDataToSave, buffer); - } - } else { -#if BUILDFLAG(IS_CHROMEOS_ASH) - uint32_t length = engine()->GetLoadedByteSize(); - if (IsSaveDataSizeValid(length)) { - pp::VarArrayBuffer buffer(length); - if (engine()->ReadLoadedBytes(length, buffer.Map())) { - message.Set(kJSDataToSave, buffer); - } - } -#else - NOTREACHED(); -#endif // BUILDFLAG(IS_CHROMEOS_ASH) - } - - PostMessage(message); -} - void OutOfProcessInstance::SaveToFile(const std::string& token) { engine()->KillFormFocus(); ConsumeSaveToken(token); pp::PDF::SaveAs(this); } -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)); - PostMessage(message); -} - void OutOfProcessInstance::Alert(const std::string& message) { pp::PDF::ShowAlertDialog(this, message.c_str()); } @@ -1323,30 +966,6 @@ std::string OutOfProcessInstance::Prompt(const std::string& question, return result.is_string() ? result.AsString() : std::string(); } -std::string OutOfProcessInstance::GetURL() { - return url_; -} - -void OutOfProcessInstance::Email(const std::string& to, - const std::string& cc, - const std::string& bcc, - const std::string& subject, - const std::string& body) { - pp::VarDictionary message; - message.Set(pp::Var(kType), pp::Var(kJSEmailType)); - message.Set(pp::Var(kJSEmailTo), - pp::Var(net::EscapeUrlEncodedData(to, false))); - message.Set(pp::Var(kJSEmailCc), - pp::Var(net::EscapeUrlEncodedData(cc, false))); - message.Set(pp::Var(kJSEmailBcc), - pp::Var(net::EscapeUrlEncodedData(bcc, false))); - message.Set(pp::Var(kJSEmailSubject), - pp::Var(net::EscapeUrlEncodedData(subject, false))); - message.Set(pp::Var(kJSEmailBody), - pp::Var(net::EscapeUrlEncodedData(body, false))); - PostMessage(message); -} - void OutOfProcessInstance::Print() { if (!engine() || (!engine()->HasPermission(PDFEngine::PERMISSION_PRINT_LOW_QUALITY) && @@ -1354,10 +973,10 @@ void OutOfProcessInstance::Print() { return; } - ScheduleTaskOnMainThread(base::TimeDelta(), + ScheduleTaskOnMainThread(FROM_HERE, base::BindOnce(&OutOfProcessInstance::OnPrint, weak_factory_.GetWeakPtr()), - 0); + /*result=*/0, base::TimeDelta()); } void OutOfProcessInstance::SubmitForm(const std::string& url, @@ -1378,26 +997,9 @@ void OutOfProcessInstance::FormDidOpen(int32_t result) { LOG_IF(ERROR, result != PP_OK) << "FormDidOpen failed: " << result; } -std::unique_ptr OutOfProcessInstance::CreateUrlLoader() { - if (full_) { - if (!did_call_start_loading_) { - did_call_start_loading_ = true; - pp::PDF::DidStartLoading(this); - } - - // Disable save and print until the document is fully loaded, since they - // would generate an incomplete document. Need to do this each time we - // call DidStartLoading since that resets the content restrictions. - pp::PDF::SetContentRestriction( - this, PP_CONTENT_RESTRICTION_SAVE | PP_CONTENT_RESTRICTION_PRINT); - } - - return CreateUrlLoaderInternal(); -} - std::vector -OutOfProcessInstance::SearchString(const base::char16* string, - const base::char16* term, +OutOfProcessInstance::SearchString(const char16_t* string, + const char16_t* term, bool case_sensitive) { PP_PrivateFindResult* pp_results; uint32_t count = 0; @@ -1417,57 +1019,6 @@ OutOfProcessInstance::SearchString(const base::char16* string, return results; } -void OutOfProcessInstance::DocumentLoadComplete() { - // Clear focus state for OSK. - FormTextFieldFocusChange(false); - - DCHECK_EQ(DocumentLoadState::kLoading, document_load_state()); - set_document_load_state(DocumentLoadState::kComplete); - UserMetricsRecordAction("PDF.LoadSuccess"); - RecordDocumentMetrics(); - - // Note: If we are in print preview mode the scroll location is retained - // across document loads so we don't want to scroll again and override it. - if (IsPrintPreview()) { - if (IsPreviewingPDF(print_preview_page_count_)) { - SendPrintPreviewLoadedNotification(); - } else { - DCHECK_EQ(0, print_preview_loaded_page_count_); - print_preview_loaded_page_count_ = 1; - AppendBlankPrintPreviewPages(); - } - OnGeometryChanged(0, 0); - } - - SendAttachments(); - SendBookmarks(); - SendMetadata(); - SendLoadingProgress(/*percentage=*/100); - - if (accessibility_state() == AccessibilityState::kPending) - LoadAccessibility(); - - if (!full_) - return; - - if (did_call_start_loading_) { - pp::PDF::DidStopLoading(this); - did_call_start_loading_ = false; - } - - int content_restrictions = - PP_CONTENT_RESTRICTION_CUT | PP_CONTENT_RESTRICTION_PASTE; - if (!engine()->HasPermission(PDFEngine::PERMISSION_COPY)) - content_restrictions |= PP_CONTENT_RESTRICTION_COPY; - - if (!engine()->HasPermission(PDFEngine::PERMISSION_PRINT_LOW_QUALITY) && - !engine()->HasPermission(PDFEngine::PERMISSION_PRINT_HIGH_QUALITY)) { - content_restrictions |= PP_CONTENT_RESTRICTION_PRINT; - } - - pp::PDF::SetContentRestriction(this, content_restrictions); -} - void OutOfProcessInstance::RotateClockwise() { engine()->RotateClockwise(); } @@ -1476,43 +1027,6 @@ void OutOfProcessInstance::RotateCounterclockwise() { engine()->RotateCounterclockwise(); } -// static -std::string OutOfProcessInstance::GetFileNameFromUrl(const std::string& url) { - // Generate a file name. Unfortunately, MIME type can't be provided, since it - // requires IO. - base::string16 file_name = net::GetSuggestedFilename( - GURL(url), /*content_disposition=*/std::string(), - /*referrer_charset=*/std::string(), /*suggested_name=*/std::string(), - /*mime_type=*/std::string(), /*default_name=*/std::string()); - return base::UTF16ToUTF8(file_name); -} - -void OutOfProcessInstance::HandleGetPasswordCompleteMessage( - const pp::VarDictionary& dict) { - if (!password_callback_ || !dict.Get(kJSPassword).is_string()) { - NOTREACHED(); - return; - } - - std::move(password_callback_).Run(dict.Get(kJSPassword).AsString()); -} - -void OutOfProcessInstance::HandleGetThumbnailMessage( - const pp::VarDictionary& dict) { - if (!dict.Get(pp::Var(kJSGetThumbnailPage)).is_number() || - !dict.Get(pp::Var(kJSMessageId)).is_string()) { - NOTREACHED(); - return; - } - - const int page_index = dict.Get(pp::Var(kJSGetThumbnailPage)).AsInt(); - engine()->RequestThumbnail( - page_index, device_scale(), - base::BindOnce(&OutOfProcessInstance::SendThumbnail, - weak_factory_.GetWeakPtr(), - dict.Get(pp::Var(kJSMessageId)).AsString())); -} - void OutOfProcessInstance::HandleLoadPreviewPageMessage( const pp::VarDictionary& dict) { if (!(dict.Get(pp::Var(kJSPreviewPageUrl)).is_string() && @@ -1565,17 +1079,17 @@ void OutOfProcessInstance::HandleResetPrintPreviewModeMessage( print_preview_page_count_ = print_preview_page_count; print_preview_loaded_page_count_ = 0; - url_ = url; + set_url(url); preview_pages_info_ = base::queue(); preview_document_load_state_ = DocumentLoadState::kComplete; set_document_load_state(DocumentLoadState::kLoading); - LoadUrl(url_, /*is_print_preview=*/false); + LoadUrl(GetURL(), /*is_print_preview=*/false); preview_engine_.reset(); InitializeEngine(PDFiumFormFiller::ScriptOption::kNoJavaScript); engine()->SetGrayscale(dict.Get(pp::Var(kJSPrintPreviewGrayscale)).AsBool()); - engine()->New(url_.c_str(), /*headers=*/nullptr); + engine()->New(GetURL().c_str(), /*headers=*/nullptr); - paint_manager().InvalidateRect(gfx::Rect(plugin_size())); + paint_manager().InvalidateRect(gfx::Rect(plugin_rect().size())); } void OutOfProcessInstance::HandleSaveAttachmentMessage( @@ -1634,7 +1148,7 @@ void OutOfProcessInstance::HandleSaveMessage(const pp::VarDictionary& dict) { case SaveRequestType::kOriginal: pp::PDF::SetPluginCanSave(this, false); SaveToFile(dict.Get(pp::Var(kJSToken)).AsString()); - pp::PDF::SetPluginCanSave(this, edit_mode_); + pp::PDF::SetPluginCanSave(this, edit_mode()); break; case SaveRequestType::kEdited: SaveToBuffer(dict.Get(pp::Var(kJSToken)).AsString()); @@ -1642,24 +1156,6 @@ void OutOfProcessInstance::HandleSaveMessage(const pp::VarDictionary& dict) { } } -void OutOfProcessInstance::HandleUpdateScrollMessage( - const pp::VarDictionary& dict) { - if (!dict.Get(pp::Var(kJSUpdateScrollX)).is_number() || - !dict.Get(pp::Var(kJSUpdateScrollY)).is_number()) { - NOTREACHED(); - return; - } - - if (stop_scrolling()) { - return; - } - - int x = dict.Get(pp::Var(kJSUpdateScrollX)).AsInt(); - int y = dict.Get(pp::Var(kJSUpdateScrollY)).AsInt(); - scroll_position_ = gfx::Point(x, y); - UpdateScroll(); -} - void OutOfProcessInstance::PreviewDocumentLoadComplete() { if (preview_document_load_state_ != DocumentLoadState::kLoading || preview_pages_info_.empty()) { @@ -1678,22 +1174,6 @@ void OutOfProcessInstance::PreviewDocumentLoadComplete() { LoadNextPreviewPage(); } -void OutOfProcessInstance::DocumentLoadFailed() { - DCHECK_EQ(DocumentLoadState::kLoading, document_load_state()); - UserMetricsRecordAction("PDF.LoadFailure"); - - if (did_call_start_loading_) { - pp::PDF::DidStopLoading(this); - did_call_start_loading_ = false; - } - - set_document_load_state(DocumentLoadState::kFailed); - paint_manager().InvalidateRect(gfx::Rect(plugin_size())); - - // Send a progress value of -1 to indicate a failure. - SendLoadingProgress(-1); -} - void OutOfProcessInstance::PreviewDocumentLoadFailed() { UserMetricsRecordAction("PDF.PreviewDocumentLoadFailure"); if (preview_document_load_state_ != DocumentLoadState::kLoading || @@ -1723,7 +1203,7 @@ void OutOfProcessInstance::DocumentHasUnsupportedFeature( } // Since we use an info bar, only do this for full frame plugins.. - if (!full_) + if (!full_frame()) return; if (told_browser_about_unsupported_feature_) @@ -1733,43 +1213,6 @@ void OutOfProcessInstance::DocumentHasUnsupportedFeature( pp::PDF::HasUnsupportedFeature(this); } -void OutOfProcessInstance::DocumentLoadProgress(uint32_t available, - uint32_t doc_size) { - double progress = 0.0; - if (doc_size) { - progress = 100.0 * static_cast(available) / doc_size; - } else { - // Document size is unknown. Use heuristics. - // We'll make progress logarithmic from 0 to 100M. - static const double kFactor = log(100000000.0) / 100.0; - if (available > 0) - progress = std::min(log(static_cast(available)) / kFactor, 100.0); - } - - // We send 100% load progress in DocumentLoadComplete. - if (progress >= 100) - return; - - // Avoid sending too many progress messages over PostMessage. - if (progress > last_progress_sent_ + 1) { - last_progress_sent_ = progress; - SendLoadingProgress(progress); - } -} - -void OutOfProcessInstance::FormTextFieldFocusChange(bool in_focus) { - if (!text_input_) - return; - - pp::VarDictionary message; - message.Set(pp::Var(kType), pp::Var(kJSFieldFocusType)); - message.Set(pp::Var(kJSFieldFocus), pp::Var(in_focus)); - PostMessage(message); - - text_input_->SetTextInputType(in_focus ? PP_TEXTINPUT_TYPE_DEV_TEXT - : PP_TEXTINPUT_TYPE_DEV_NONE); -} - void OutOfProcessInstance::ResetRecentlySentFindUpdate(int32_t /* unused */) { recently_sent_find_update_ = false; } @@ -1840,15 +1283,8 @@ bool OutOfProcessInstance::IsPrintPreview() { return is_print_preview_; } -void OutOfProcessInstance::IsSelectingChanged(bool is_selecting) { - pp::VarDictionary message; - message.Set(kType, kJSSetIsSelectingType); - message.Set(kJSIsSelecting, pp::Var(is_selecting)); - PostMessage(message); -} - void OutOfProcessInstance::EnteredEditMode() { - edit_mode_ = true; + set_edit_mode(true); pp::PDF::SetPluginCanSave(this, true); pp::VarDictionary message; @@ -1856,13 +1292,6 @@ void OutOfProcessInstance::EnteredEditMode() { PostMessage(message); } -void OutOfProcessInstance::DocumentFocusChanged(bool document_has_focus) { - pp::VarDictionary message; - message.Set(pp::Var(kType), pp::Var(kJSDocumentFocusChangedType)); - message.Set(pp::Var(kJSDocumentHasFocus), pp::Var(document_has_focus)); - PostMessage(message); -} - void OutOfProcessInstance::SetSelectedText(const std::string& selected_text) { pp::PDF::SetSelectedText(this, selected_text.c_str()); } @@ -1888,12 +1317,12 @@ bool OutOfProcessInstance::BindPaintGraphics(Graphics& graphics) { } void OutOfProcessInstance::ScheduleTaskOnMainThread( - base::TimeDelta delay, + const base::Location& from_here, ResultCallback callback, int32_t result, - const base::Location& from_here) { + base::TimeDelta delay) { int64_t delay_in_msec = delay.InMilliseconds(); - DCHECK(delay_in_msec <= INT32_MAX); + DCHECK_LE(delay_in_msec, INT32_MAX); pp::Module::Get()->core()->CallOnMainThread( static_cast(delay_in_msec), PPCompletionCallbackFromResultCallback(std::move(callback)), result); @@ -1948,142 +1377,37 @@ void OutOfProcessInstance::LoadNextPreviewPage() { } } -void OutOfProcessInstance::SendPrintPreviewLoadedNotification() { - pp::VarDictionary loaded_message; - loaded_message.Set(pp::Var(kType), pp::Var(kJSPreviewLoadedType)); - PostMessage(loaded_message); -} - -void OutOfProcessInstance::SendAttachments() { - pp::VarArray attachments = GetDocumentAttachments(); - if (attachments.GetLength() == 0) +void OutOfProcessInstance::DidStartLoading() { + if (did_call_start_loading_) return; - pp::VarDictionary attachments_message; - attachments_message.Set(pp::Var(kType), pp::Var(kJSAttachmentsType)); - attachments_message.Set(pp::Var(kJSAttachmentsData), attachments); - - PostMessage(attachments_message); + pp::PDF::DidStartLoading(this); + did_call_start_loading_ = true; } -void OutOfProcessInstance::SendBookmarks() { - base::Value bookmarks = engine()->GetBookmarks(); - DCHECK(bookmarks.is_list()); - if (bookmarks.GetList().empty()) +void OutOfProcessInstance::DidStopLoading() { + if (!did_call_start_loading_) return; - pp::VarDictionary bookmarks_message; - bookmarks_message.Set(pp::Var(kType), pp::Var(kJSBookmarksType)); - bookmarks_message.Set(pp::Var(kJSBookmarksData), VarFromValue(bookmarks)); - - PostMessage(bookmarks_message); + pp::PDF::DidStopLoading(this); + did_call_start_loading_ = false; } -void OutOfProcessInstance::SendMetadata() { - pp::VarDictionary metadata_message; - metadata_message.Set(pp::Var(kType), pp::Var(kJSMetadataType)); - - const DocumentMetadata& document_metadata = engine()->GetDocumentMetadata(); - pp::VarDictionary metadata_data; - - base::string16 version = GetFormattedVersion(document_metadata.version); - if (!version.empty()) - metadata_data.Set(pp::Var(kJSVersion), pp::Var(base::UTF16ToUTF8(version))); - - metadata_data.Set( - pp::Var(kJSFileSize), - base::UTF16ToUTF8(ui::FormatBytes(document_metadata.size_bytes))); - - metadata_data.Set(pp::Var(kJSLinearized), - pp::Var(document_metadata.linearized)); - - if (!document_metadata.title.empty()) - metadata_data.Set(pp::Var(kJSTitle), pp::Var(document_metadata.title)); - - if (!document_metadata.author.empty()) - metadata_data.Set(pp::Var(kJSAuthor), pp::Var(document_metadata.author)); - - if (!document_metadata.subject.empty()) - metadata_data.Set(pp::Var(kJSSubject), pp::Var(document_metadata.subject)); - - if (!document_metadata.keywords.empty()) { - metadata_data.Set(pp::Var(kJSKeywords), - pp::Var(document_metadata.keywords)); - } - - if (!document_metadata.creator.empty()) - metadata_data.Set(pp::Var(kJSCreator), pp::Var(document_metadata.creator)); - - if (!document_metadata.producer.empty()) { - metadata_data.Set(pp::Var(kJSProducer), - pp::Var(document_metadata.producer)); - } - - if (!document_metadata.creation_date.is_null()) { - metadata_data.Set( - pp::Var(kJSCreationDate), - pp::Var(base::UTF16ToUTF8(base::TimeFormatShortDateAndTime( - document_metadata.creation_date)))); - } - - if (!document_metadata.mod_date.is_null()) { - metadata_data.Set( - pp::Var(kJSModDate), - pp::Var(base::UTF16ToUTF8( - base::TimeFormatShortDateAndTime(document_metadata.mod_date)))); +void OutOfProcessInstance::OnPrintPreviewLoaded() { + // Scroll location is retained across document loads in print preview mode, so + // there's no need to override the scroll position by scrolling again. + if (IsPreviewingPDF(print_preview_page_count_)) { + SendPrintPreviewLoadedNotification(); + } else { + DCHECK_EQ(0, print_preview_loaded_page_count_); + print_preview_loaded_page_count_ = 1; + AppendBlankPrintPreviewPages(); } - - metadata_data.Set(pp::Var(kJSPageSize), - pp::Var(base::UTF16ToUTF8( - FormatPageSize(engine()->GetUniformPageSizePoints())))); - - metadata_data.Set( - pp::Var(kJSCanSerializeDocument), - pp::Var(IsSaveDataSizeValid(engine()->GetLoadedByteSize()))); - - metadata_message.Set(pp::Var(kJSMetadataData), metadata_data); - PostMessage(metadata_message); -} - -void OutOfProcessInstance::SendLoadingProgress(double percentage) { - DCHECK(percentage == -1 || (percentage >= 0 && percentage <= 100)); - pp::VarDictionary progress_message; - progress_message.Set(pp::Var(kType), pp::Var(kJSLoadProgressType)); - progress_message.Set(pp::Var(kJSProgressPercentage), pp::Var(percentage)); - PostMessage(progress_message); -} - -void OutOfProcessInstance::SendThumbnail(const std::string& message_id, - Thumbnail thumbnail) { - pp::VarDictionary reply; - reply.Set(pp::Var(kType), pp::Var(kJSGetThumbnailReplyType)); - reply.Set(pp::Var(kJSMessageId), message_id); - - const SkBitmap& bitmap = thumbnail.bitmap(); - const size_t buffer_size = bitmap.computeByteSize(); - pp::VarArrayBuffer buffer(buffer_size); - memcpy(buffer.Map(), bitmap.getPixels(), buffer_size); - reply.Set(pp::Var(kJSGetThumbnailImageData), buffer); - buffer.Unmap(); - - reply.Set(pp::Var(kJSGetThumbnailWidth), bitmap.width()); - reply.Set(pp::Var(kJSGetThumbnailHeight), bitmap.height()); - - PostMessage(reply); + OnGeometryChanged(0, 0); } -void OutOfProcessInstance::RecordDocumentMetrics() { - const DocumentMetadata& document_metadata = engine()->GetDocumentMetadata(); - HistogramEnumeration("PDF.Version", document_metadata.version); - HistogramCustomCounts("PDF.PageCount", document_metadata.page_count, 1, - 1000000, 50); - HistogramEnumeration("PDF.HasAttachment", document_metadata.has_attachments - ? PdfHasAttachment::kYes - : PdfHasAttachment::kNo); - HistogramEnumeration("PDF.IsTagged", document_metadata.tagged - ? PdfIsTagged::kYes - : PdfIsTagged::kNo); - HistogramEnumeration("PDF.FormType", document_metadata.form_type); +void OutOfProcessInstance::SetContentRestrictions(int content_restrictions) { + pp::PDF::SetContentRestriction(this, content_restrictions); } void OutOfProcessInstance::UserMetricsRecordAction(const std::string& action) { @@ -2128,23 +1452,6 @@ bool OutOfProcessInstance::SendInputEventToEngine(const pp::InputEvent& event) { } } -template -void OutOfProcessInstance::HistogramEnumeration(const char* name, T sample) { - if (IsPrintPreview()) - return; - base::UmaHistogramEnumeration(name, sample); -} - -void OutOfProcessInstance::HistogramCustomCounts(const char* name, - int32_t sample, - int32_t min, - int32_t max, - uint32_t bucket_count) { - if (IsPrintPreview()) - return; - base::UmaHistogramCustomCounts(name, sample, min, max, bucket_count); -} - void OutOfProcessInstance::OnPrint(int32_t /*unused_but_required*/) { pp::PDF::Print(this); } diff --git a/chromium/pdf/out_of_process_instance.h b/chromium/pdf/out_of_process_instance.h index dbc019093c4..e281335bdba 100644 --- a/chromium/pdf/out_of_process_instance.h +++ b/chromium/pdf/out_of_process_instance.h @@ -16,7 +16,6 @@ #include "base/callback.h" #include "base/containers/queue.h" -#include "base/location.h" #include "base/memory/weak_ptr.h" #include "pdf/pdf_view_plugin_base.h" #include "pdf/preview_mode_client.h" @@ -26,18 +25,16 @@ #include "ppapi/cpp/instance.h" #include "ppapi/cpp/private/find_private.h" #include "third_party/skia/include/core/SkBitmap.h" -#include "ui/gfx/geometry/point.h" +#include "ui/base/cursor/mojom/cursor_type.mojom-shared.h" #include "ui/gfx/geometry/rect.h" namespace gfx { class Size; -class Vector2d; } // namespace gfx namespace pp { class Size; class TextInput_Dev; -class VarArray; class VarDictionary; } // namespace pp @@ -45,7 +42,6 @@ namespace chrome_pdf { class Graphics; class PDFiumEngine; -class Thumbnail; class UrlLoader; class OutOfProcessInstance : public PdfViewPluginBase, @@ -99,65 +95,35 @@ class OutOfProcessInstance : public PdfViewPluginBase, void FlushCallback(int32_t result); // PdfViewPluginBase: - void ProposeDocumentLayout(const DocumentLayout& layout) override; - void DidScroll(const gfx::Vector2d& offset) override; - void ScrollToX(int x_in_screen_coords) override; - void ScrollToY(int y_in_screen_coords) override; - void ScrollBy(const gfx::Vector2d& scroll_delta) override; - void ScrollToPage(int page) override; - void NavigateTo(const std::string& url, - WindowOpenDisposition disposition) override; - void NavigateToDestination(int page, - const float* x, - const float* y, - const float* zoom) override; - void UpdateCursor(PP_CursorType_Dev cursor) override; + void UpdateCursor(ui::mojom::CursorType cursor_type) override; void UpdateTickMarks(const std::vector& tickmarks) override; void NotifyNumberOfFindResultsChanged(int total, bool final_result) override; void NotifySelectedFindResultChanged(int current_find_index) override; - void NotifyTouchSelectionOccurred() override; - void GetDocumentPassword( - base::OnceCallback callback) override; - void Beep() override; void Alert(const std::string& message) override; bool Confirm(const std::string& message) override; std::string Prompt(const std::string& question, const std::string& default_answer) override; - std::string GetURL() override; - void Email(const std::string& to, - const std::string& cc, - const std::string& bcc, - const std::string& subject, - const std::string& body) override; void Print() override; void SubmitForm(const std::string& url, const void* data, int length) override; - std::unique_ptr CreateUrlLoader() override; - std::vector SearchString(const base::char16* string, - const base::char16* term, + std::vector SearchString(const char16_t* string, + const char16_t* term, bool case_sensitive) override; - void DocumentLoadComplete() override; - void DocumentLoadFailed() override; pp::Instance* GetPluginInstance() override; void DocumentHasUnsupportedFeature(const std::string& feature) override; - void DocumentLoadProgress(uint32_t available, uint32_t doc_size) override; - void FormTextFieldFocusChange(bool in_focus) override; bool IsPrintPreview() override; - void IsSelectingChanged(bool is_selecting) override; void SelectionChanged(const gfx::Rect& left, const gfx::Rect& right) override; void EnteredEditMode() override; - void DocumentFocusChanged(bool document_has_focus) override; void SetSelectedText(const std::string& selected_text) override; void SetLinkUnderCursor(const std::string& link_under_cursor) override; bool IsValidLink(const std::string& url) override; std::unique_ptr CreatePaintGraphics(const gfx::Size& size) override; bool BindPaintGraphics(Graphics& graphics) override; - void ScheduleTaskOnMainThread( - base::TimeDelta delay, - ResultCallback callback, - int32_t result, - const base::Location& from_here = base::Location::Current()) override; + void ScheduleTaskOnMainThread(const base::Location& from_here, + ResultCallback callback, + int32_t result, + base::TimeDelta delay) override; // PreviewModeClient::Client: void PreviewDocumentLoadComplete() override; @@ -167,10 +133,6 @@ class OutOfProcessInstance : public PdfViewPluginBase, void RotateClockwise(); void RotateCounterclockwise(); - // Creates a file name for saving a PDF file, given the source URL. Exposed - // for testing. - static std::string GetFileNameFromUrl(const std::string& url); - protected: // PdfViewPluginBase: base::WeakPtr GetWeakPtr() override; @@ -181,6 +143,7 @@ class OutOfProcessInstance : public PdfViewPluginBase, void SendMessage(base::Value message) override; void InitImageData(const gfx::Size& size) override; Image GetPluginImageData() const override; + void SetFormFieldInFocus(bool in_focus) override; void SetAccessibilityDocInfo(const AccessibilityDocInfo& doc_info) override; void SetAccessibilityPageInfo(AccessibilityPageInfo page_info, std::vector text_runs, @@ -188,40 +151,26 @@ class OutOfProcessInstance : public PdfViewPluginBase, AccessibilityPageObjects page_objects) override; void SetAccessibilityViewportInfo( const AccessibilityViewportInfo& viewport_info) override; + void SetContentRestrictions(int content_restrictions) override; + void DidStartLoading() override; + void DidStopLoading() override; + void OnPrintPreviewLoaded() override; + void UserMetricsRecordAction(const std::string& action) override; private: // Message handlers. - void HandleGetPasswordCompleteMessage(const pp::VarDictionary& dict); - void HandleGetThumbnailMessage(const pp::VarDictionary& dict); void HandleLoadPreviewPageMessage(const pp::VarDictionary& dict); void HandleResetPrintPreviewModeMessage(const pp::VarDictionary& dict); void HandleSaveAttachmentMessage(const pp::VarDictionary& dict); void HandleSaveMessage(const pp::VarDictionary& dict); - void HandleUpdateScrollMessage(const pp::VarDictionary& dict); - - // Repaints plugin contents based on the current scroll position. - void UpdateScroll(); void ResetRecentlySentFindUpdate(int32_t); - // Returns a VarArray of Attachments. Each Attachment is a VarDictionary - // which contains the following key/values: - // - "name" - a string Var. - // - "size" - an int Var (-1 indicates the attachment file is too big to be - // downloaded). - // - "readable" a bool Var. - pp::VarArray GetDocumentAttachments(); - bool CanSaveEdits() const; void SaveToFile(const std::string& token); - void SaveToBuffer(const std::string& token); - void ConsumeSaveToken(const std::string& token); void FormDidOpen(int32_t result); - void RecordDocumentMetrics(); - void UserMetricsRecordAction(const std::string& action); - // Must match SaveRequestType in chrome/browser/resources/pdf/constants.js. enum class SaveRequestType { kAnnotation = 0, @@ -245,53 +194,6 @@ class OutOfProcessInstance : public PdfViewPluginBase, // Called after a preview page has loaded or failed to load. void LoadNextPreviewPage(); - // Send a notification that the print preview has loaded. - void SendPrintPreviewLoadedNotification(); - - // Send attachments. - void SendAttachments(); - - // Send bookmarks. - void SendBookmarks(); - - // Send document metadata. - void SendMetadata(); - - // Send the loading progress, where |percentage| represents the progress, or - // -1 for loading error. - void SendLoadingProgress(double percentage); - - // Sends the thumbnail image data. - void SendThumbnail(const std::string& message_id, Thumbnail thumbnail); - - // These values are persisted to logs. Entries should not be renumbered and - // numeric values should never be reused. - enum class PdfHasAttachment { - kNo = 0, - kYes = 1, - kMaxValue = kYes, - }; - - // These values are persisted to logs. Entries should not be renumbered and - // numeric values should never be reused. - enum class PdfIsTagged { - kNo = 0, - kYes = 1, - kMaxValue = kYes, - }; - - // Add a sample to an enumerated histogram and filter out print preview usage. - template - void HistogramEnumeration(const char* name, T sample); - - // Add a sample to a custom counts histogram and filter out print preview - // usage. - void HistogramCustomCounts(const char* name, - int32_t sample, - int32_t min, - int32_t max, - uint32_t bucket_count); - // Callback to print without re-entrancy issues. void OnPrint(int32_t /*unused_but_required*/); @@ -299,14 +201,11 @@ class OutOfProcessInstance : public PdfViewPluginBase, // or not. bool SendInputEventToEngine(const pp::InputEvent& event); - // The Pepper image data that is in sync with image_data(). + // The Pepper image data that is in sync with mutable_image_data(). pp::ImageData pepper_image_data_; - // The current cursor. - PP_CursorType_Dev cursor_ = PP_CURSORTYPE_POINTER; - - // The scroll position in CSS pixels. - gfx::Point scroll_position_; + // The current cursor type. + ui::mojom::CursorType cursor_type_ = ui::mojom::CursorType::kPointer; // True if the plugin is full-page. bool full_ = false; @@ -342,14 +241,9 @@ class OutOfProcessInstance : public PdfViewPluginBase, // interface which has very limited access to the pp::Instance. std::unique_ptr preview_engine_; - std::string url_; - // Used for submitting forms. std::unique_ptr form_loader_; - // The callback for receiving the password from the page. - base::OnceCallback password_callback_; - DocumentLoadState preview_document_load_state_ = DocumentLoadState::kComplete; // Used so that we only tell the browser once about an unsupported feature, to @@ -385,9 +279,6 @@ class OutOfProcessInstance : public PdfViewPluginBase, // http://crbug.com/132565 std::unique_ptr text_input_; - // The last document load progress value sent to the web page. - double last_progress_sent_ = 0.0; - // Whether an update to the number of find results found was sent less than // |kFindResultCooldownMs| milliseconds ago. bool recently_sent_find_update_ = false; @@ -400,8 +291,6 @@ class OutOfProcessInstance : public PdfViewPluginBase, // document finishes loading. bool did_call_start_loading_ = false; - bool edit_mode_ = false; - base::WeakPtrFactory weak_factory_{this}; }; diff --git a/chromium/pdf/out_of_process_instance_unittest.cc b/chromium/pdf/out_of_process_instance_unittest.cc deleted file mode 100644 index 88705dbb45d..00000000000 --- a/chromium/pdf/out_of_process_instance_unittest.cc +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2019 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/out_of_process_instance.h" - -#include - -#include "testing/gtest/include/gtest/gtest.h" - -namespace chrome_pdf { - -TEST(OutOfProcessInstanceTest, GetFileNameFromUrl) { - EXPECT_EQ("b.pdf", - OutOfProcessInstance::GetFileNameFromUrl("https://test/a/b.pdf")); - - // File extensions should be kept as-is. - EXPECT_EQ("b.hat", - OutOfProcessInstance::GetFileNameFromUrl("https://test/a/b.hat")); - - // Most escaped characters should be unescaped. - EXPECT_EQ("a b.pdf", OutOfProcessInstance::GetFileNameFromUrl( - "https://test/%61%20b.pdf")); - - // Escaped file path delimiters and control codes should be replaced by a - // placeholder. - EXPECT_EQ("a_b_.pdf", OutOfProcessInstance::GetFileNameFromUrl( - "https://test/a%2Fb%01.pdf")); - - // UTF-8 characters, including ones left escaped by UnescapeURLComponent() for - // security reasons, are allowed in file paths. - EXPECT_EQ("\xF0\x9F\x94\x92", OutOfProcessInstance::GetFileNameFromUrl( - "https://test/%F0%9F%94%92")); -} - -} // namespace chrome_pdf diff --git a/chromium/pdf/paint_manager.cc b/chromium/pdf/paint_manager.cc index 1b71b3a17ef..ef492c140da 100644 --- a/chromium/pdf/paint_manager.cc +++ b/chromium/pdf/paint_manager.cc @@ -13,6 +13,7 @@ #include "base/bind.h" #include "base/callback.h" #include "base/check.h" +#include "base/location.h" #include "base/time/time.h" #include "pdf/paint_ready_rect.h" #include "pdf/ppapi_migration/callback.h" @@ -163,10 +164,10 @@ void PaintManager::EnsureCallbackPending() { return; client_->ScheduleTaskOnMainThread( - base::TimeDelta(), + FROM_HERE, base::BindOnce(&PaintManager::OnManualCallbackComplete, weak_factory_.GetWeakPtr()), - 0); + /*result=*/0, base::TimeDelta()); manual_callback_pending_ = true; } diff --git a/chromium/pdf/paint_manager.h b/chromium/pdf/paint_manager.h index a471bafaaeb..100d27f897e 100644 --- a/chromium/pdf/paint_manager.h +++ b/chromium/pdf/paint_manager.h @@ -10,14 +10,14 @@ #include #include -#include "base/location.h" #include "base/memory/weak_ptr.h" +#include "base/time/time.h" #include "pdf/paint_aggregator.h" #include "pdf/ppapi_migration/callback.h" #include "ui/gfx/geometry/size.h" namespace base { -class TimeDelta; +class Location; } // namespace base namespace gfx { @@ -78,11 +78,10 @@ class PaintManager { // not always needed. `delay` should be no longer than `INT32_MAX` // milliseconds for the Pepper plugin implementation to prevent integer // overflow. - virtual void ScheduleTaskOnMainThread( - base::TimeDelta delay, - ResultCallback callback, - int32_t result, - const base::Location& from_here = base::Location::Current()) = 0; + virtual void ScheduleTaskOnMainThread(const base::Location& from_here, + ResultCallback callback, + int32_t result, + base::TimeDelta delay) = 0; protected: // You shouldn't be doing deleting through this interface. @@ -92,8 +91,9 @@ class PaintManager { // The Client is a non-owning pointer and must remain valid (normally the // object implementing the Client interface will own the paint manager). // - // You will need to call SetSize before this class will do anything. Normally - // you do this from the ViewChanged method of your plugin instance. + // You will need to call SetSize() before this class will do anything. + // Normally you do this from UpdateGeometryOnViewChanged() of your plugin + // instance. explicit PaintManager(Client* client); PaintManager(const PaintManager&) = delete; PaintManager& operator=(const PaintManager&) = delete; diff --git a/chromium/pdf/pdf_engine.h b/chromium/pdf/pdf_engine.h index 8aea32927b7..9ecba9d5f25 100644 --- a/chromium/pdf/pdf_engine.h +++ b/chromium/pdf/pdf_engine.h @@ -13,21 +13,19 @@ #include "base/callback.h" #include "base/containers/span.h" -#include "base/location.h" #include "base/optional.h" -#include "base/strings/string16.h" #include "base/time/time.h" #include "base/values.h" #include "build/build_config.h" #include "build/chromeos_buildflags.h" #include "pdf/document_layout.h" #include "pdf/ppapi_migration/callback.h" -#include "ppapi/c/dev/pp_cursor_type_dev.h" #include "ppapi/c/dev/ppp_printing_dev.h" #include "ppapi/cpp/completion_callback.h" #include "ppapi/cpp/private/pdf.h" #include "ppapi/cpp/url_loader.h" #include "third_party/skia/include/core/SkColor.h" +#include "ui/base/cursor/mojom/cursor_type.mojom-forward.h" #include "ui/base/window_open_disposition.h" #include "ui/gfx/geometry/point_f.h" #include "ui/gfx/geometry/rect.h" @@ -46,6 +44,10 @@ typedef void (*PDFEnsureTypefaceCharactersAccessible)(const LOGFONT* font, struct PP_PdfPrintSettings_Dev; class SkBitmap; +namespace base { +class Location; +} // namespace base + namespace gfx { class Point; class Rect; @@ -120,7 +122,7 @@ class PDFEngine { // The interface that's provided to the rendering engine. class Client { public: - virtual ~Client() {} + virtual ~Client() = default; // Proposes a document layout to the client. For the proposed layout to // become effective, the client must call PDFEngine::ApplyDocumentLayout() @@ -136,11 +138,11 @@ class PDFEngine { // Scroll the horizontal/vertical scrollbars to a given position. // Values are in screen coordinates, where 0 is the top/left of the document // and a positive value is the distance in pixels from that line. - virtual void ScrollToX(int x_in_screen_coords) {} - virtual void ScrollToY(int y_in_screen_coords) {} + virtual void ScrollToX(int x_screen_coords) {} + virtual void ScrollToY(int y_screen_coords) {} // Scroll by a given delta relative to the current position. - virtual void ScrollBy(const gfx::Vector2d& scroll_delta) {} + virtual void ScrollBy(const gfx::Vector2d& delta) {} // Scroll to zero-based |page|. virtual void ScrollToPage(int page) {} @@ -157,7 +159,7 @@ class PDFEngine { const float* zoom) {} // Updates the cursor. - virtual void UpdateCursor(PP_CursorType_Dev cursor) {} + virtual void UpdateCursor(ui::mojom::CursorType cursor_type) {} // Updates the tick marks in the vertical scrollbar. virtual void UpdateTickMarks(const std::vector& tickmarks) {} @@ -222,8 +224,8 @@ class PDFEngine { int length; }; virtual std::vector SearchString( - const base::char16* string, - const base::char16* term, + const char16_t* string, + const char16_t* term, bool case_sensitive) = 0; // Notifies the client that the document has finished loading. @@ -250,7 +252,7 @@ class PDFEngine { virtual SkColor GetBackgroundColor() = 0; // Sets selection status. - virtual void IsSelectingChanged(bool is_selecting) {} + virtual void SetIsSelecting(bool is_selecting) {} virtual void SelectionChanged(const gfx::Rect& left, const gfx::Rect& right) {} @@ -279,14 +281,13 @@ class PDFEngine { // not always needed. `delay` should be no longer than `INT32_MAX` // milliseconds for the Pepper plugin implementation to prevent integer // overflow. - virtual void ScheduleTaskOnMainThread( - base::TimeDelta delay, - ResultCallback callback, - int32_t result, - const base::Location& from_here = base::Location::Current()) = 0; + virtual void ScheduleTaskOnMainThread(const base::Location& from_here, + ResultCallback callback, + int32_t result, + base::TimeDelta delay) = 0; }; - virtual ~PDFEngine() {} + virtual ~PDFEngine() = default; // Most of these functions are similar to the Pepper functions of the same // name, so not repeating the description here unless it's different. diff --git a/chromium/pdf/pdf_view_plugin_base.cc b/chromium/pdf/pdf_view_plugin_base.cc index 51cdf43e962..b77e53a2619 100644 --- a/chromium/pdf/pdf_view_plugin_base.cc +++ b/chromium/pdf/pdf_view_plugin_base.cc @@ -17,8 +17,12 @@ #include "base/check.h" #include "base/check_op.h" #include "base/containers/fixed_flat_map.h" +#include "base/containers/span.h" #include "base/feature_list.h" +#include "base/i18n/time_formatting.h" +#include "base/location.h" #include "base/memory/weak_ptr.h" +#include "base/metrics/histogram_functions.h" #include "base/notreached.h" #include "base/numerics/ranges.h" #include "base/numerics/safe_conversions.h" @@ -27,18 +31,28 @@ #include "base/strings/string_util.h" #include "base/time/time.h" #include "base/values.h" +#include "build/chromeos_buildflags.h" +#include "net/base/escape.h" #include "pdf/accessibility.h" #include "pdf/accessibility_structs.h" +#include "pdf/content_restriction.h" +#include "pdf/document_layout.h" +#include "pdf/document_metadata.h" #include "pdf/paint_ready_rect.h" #include "pdf/pdf_features.h" #include "pdf/pdfium/pdfium_engine.h" #include "pdf/ppapi_migration/image.h" #include "pdf/ppapi_migration/url_loader.h" +#include "pdf/ui/document_properties.h" +#include "pdf/ui/file_name.h" +#include "pdf/ui/thumbnail.h" #include "third_party/skia/include/core/SkBitmap.h" #include "third_party/skia/include/core/SkColor.h" +#include "ui/base/text/bytes_formatting.h" #include "ui/gfx/geometry/point_f.h" #include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/size.h" +#include "ui/gfx/geometry/vector2d.h" #include "ui/gfx/skia_util.h" namespace chrome_pdf { @@ -86,6 +100,31 @@ PdfViewPluginBase::PdfViewPluginBase() = default; PdfViewPluginBase::~PdfViewPluginBase() = default; +void PdfViewPluginBase::ProposeDocumentLayout(const DocumentLayout& layout) { + base::Value message(base::Value::Type::DICTIONARY); + message.SetStringKey("type", "documentDimensions"); + message.SetIntKey("width", layout.size().width()); + message.SetIntKey("height", layout.size().height()); + message.SetKey("layoutOptions", layout.options().ToValue()); + base::Value page_dimensions_list(base::Value::Type::LIST); + for (size_t i = 0; i < layout.page_count(); ++i) { + const gfx::Rect& page_rect = layout.page_rect(i); + base::Value page_dimensions(base::Value::Type::DICTIONARY); + page_dimensions.SetIntKey("x", page_rect.x()); + page_dimensions.SetIntKey("y", page_rect.y()); + page_dimensions.SetIntKey("width", page_rect.width()); + page_dimensions.SetIntKey("height", page_rect.height()); + page_dimensions_list.Append(std::move(page_dimensions)); + } + message.SetKey("pageDimensions", std::move(page_dimensions_list)); + SendMessage(std::move(message)); + + // Reload the accessibility tree on layout changes because the relative page + // bounds are no longer valid. + if (layout.dirty() && accessibility_state_ == AccessibilityState::kLoaded) + LoadAccessibility(); +} + void PdfViewPluginBase::Invalidate(const gfx::Rect& rect) { if (in_paint_) { deferred_invalidates_.push_back(rect); @@ -96,10 +135,234 @@ void PdfViewPluginBase::Invalidate(const gfx::Rect& rect) { paint_manager_.InvalidateRect(offset_rect); } +void PdfViewPluginBase::DidScroll(const gfx::Vector2d& offset) { + if (!image_data_.drawsNothing()) + paint_manager_.ScrollRect(available_area_, offset); +} + +void PdfViewPluginBase::ScrollToX(int x_screen_coords) { + const float x_scroll_pos = x_screen_coords / device_scale_; + + base::Value message(base::Value::Type::DICTIONARY); + message.SetStringKey("type", "setScrollPosition"); + message.SetDoubleKey("x", x_scroll_pos); + SendMessage(std::move(message)); +} + +void PdfViewPluginBase::ScrollToY(int y_screen_coords) { + const float y_scroll_pos = y_screen_coords / device_scale_; + + base::Value message(base::Value::Type::DICTIONARY); + message.SetStringKey("type", "setScrollPosition"); + message.SetDoubleKey("y", y_scroll_pos); + SendMessage(std::move(message)); +} + +void PdfViewPluginBase::ScrollBy(const gfx::Vector2d& delta) { + const float x_delta = delta.x() / device_scale_; + const float y_delta = delta.y() / device_scale_; + + base::Value message(base::Value::Type::DICTIONARY); + message.SetStringKey("type", "scrollBy"); + message.SetDoubleKey("x", x_delta); + message.SetDoubleKey("y", y_delta); + SendMessage(std::move(message)); +} + +void PdfViewPluginBase::ScrollToPage(int page) { + if (!engine_ || engine_->GetNumberOfPages() == 0) + return; + + base::Value message(base::Value::Type::DICTIONARY); + message.SetStringKey("type", "goToPage"); + message.SetIntKey("page", page); + SendMessage(std::move(message)); +} + +void PdfViewPluginBase::NavigateTo(const std::string& url, + WindowOpenDisposition disposition) { + base::Value message(base::Value::Type::DICTIONARY); + message.SetStringKey("type", "navigate"); + message.SetStringKey("url", url); + message.SetIntKey("disposition", static_cast(disposition)); + SendMessage(std::move(message)); +} + +void PdfViewPluginBase::NavigateToDestination(int page, + const float* x, + const float* y, + const float* zoom) { + base::Value message(base::Value::Type::DICTIONARY); + message.SetStringKey("type", "navigateToDestination"); + message.SetIntKey("page", page); + if (x) + message.SetDoubleKey("x", *x); + if (y) + message.SetDoubleKey("y", *y); + if (zoom) + message.SetDoubleKey("zoom", *zoom); + SendMessage(std::move(message)); +} + +void PdfViewPluginBase::NotifyTouchSelectionOccurred() { + base::Value message(base::Value::Type::DICTIONARY); + message.SetStringKey("type", "touchSelectionOccurred"); + SendMessage(std::move(message)); +} + +void PdfViewPluginBase::GetDocumentPassword( + base::OnceCallback callback) { + DCHECK(password_callback_.is_null()); + password_callback_ = std::move(callback); + + base::Value message(base::Value::Type::DICTIONARY); + message.SetStringKey("type", "getPassword"); + SendMessage(std::move(message)); +} + +void PdfViewPluginBase::Beep() { + base::Value message(base::Value::Type::DICTIONARY); + message.SetStringKey("type", "beep"); + SendMessage(std::move(message)); +} + +std::string PdfViewPluginBase::GetURL() { + return url_; +} + +void PdfViewPluginBase::Email(const std::string& to, + const std::string& cc, + const std::string& bcc, + const std::string& subject, + const std::string& body) { + base::Value message(base::Value::Type::DICTIONARY); + message.SetStringKey("type", "email"); + message.SetStringKey("to", net::EscapeUrlEncodedData(to, false)); + message.SetStringKey("cc", net::EscapeUrlEncodedData(cc, false)); + message.SetStringKey("bcc", net::EscapeUrlEncodedData(bcc, false)); + message.SetStringKey("subject", net::EscapeUrlEncodedData(subject, false)); + message.SetStringKey("body", net::EscapeUrlEncodedData(body, false)); + SendMessage(std::move(message)); +} + +std::unique_ptr PdfViewPluginBase::CreateUrlLoader() { + if (full_frame_) { + DidStartLoading(); + + // Disable save and print until the document is fully loaded, since they + // would generate an incomplete document. This needs to be done each time + // DidStartLoading() is called because that resets the content restrictions. + SetContentRestrictions(kContentRestrictionSave | kContentRestrictionPrint); + } + + return CreateUrlLoaderInternal(); +} + +void PdfViewPluginBase::DocumentLoadComplete() { + DCHECK_EQ(DocumentLoadState::kLoading, document_load_state_); + document_load_state_ = DocumentLoadState::kComplete; + + UserMetricsRecordAction("PDF.LoadSuccess"); + RecordDocumentMetrics(); + + // Clear the focus state for on-screen keyboards. + FormTextFieldFocusChange(false); + + if (IsPrintPreview()) + OnPrintPreviewLoaded(); + + SendAttachments(); + SendBookmarks(); + SendMetadata(); + SendLoadingProgress(/*percentage=*/100); + + if (accessibility_state_ == AccessibilityState::kPending) + LoadAccessibility(); + + if (!full_frame_) + return; + + DidStopLoading(); + + int content_restrictions = kContentRestrictionCut | kContentRestrictionPaste; + if (!engine()->HasPermission(PDFEngine::PERMISSION_COPY)) + content_restrictions |= kContentRestrictionCopy; + + if (!engine()->HasPermission(PDFEngine::PERMISSION_PRINT_LOW_QUALITY) && + !engine()->HasPermission(PDFEngine::PERMISSION_PRINT_HIGH_QUALITY)) { + content_restrictions |= kContentRestrictionPrint; + } + + SetContentRestrictions(content_restrictions); +} + +void PdfViewPluginBase::DocumentLoadFailed() { + DCHECK_EQ(DocumentLoadState::kLoading, document_load_state_); + document_load_state_ = DocumentLoadState::kFailed; + + UserMetricsRecordAction("PDF.LoadFailure"); + + // Send a progress value of -1 to indicate a failure. + SendLoadingProgress(-1); + + DidStopLoading(); + + paint_manager_.InvalidateRect(gfx::Rect(plugin_rect_.size())); +} + +void PdfViewPluginBase::DocumentLoadProgress(uint32_t available, + uint32_t doc_size) { + double progress = 0.0; + if (doc_size > 0) { + progress = 100.0 * static_cast(available) / doc_size; + } else { + // Use heuristics when the document size is unknown. + // Progress logarithmically from 0 to 100M. + static const double kFactor = std::log(100'000'000.0) / 100.0; + if (available > 0) + progress = + std::min(std::log(static_cast(available)) / kFactor, 100.0); + } + + // DocumentLoadComplete() will send the 100% load progress. + if (progress >= 100) + return; + + // Avoid sending too many progress messages over PostMessage. + if (progress <= last_progress_sent_ + 1) + return; + + last_progress_sent_ = progress; + SendLoadingProgress(progress); +} + +void PdfViewPluginBase::FormTextFieldFocusChange(bool in_focus) { + base::Value message(base::Value::Type::DICTIONARY); + message.SetStringKey("type", "formFocusChange"); + message.SetBoolKey("focused", in_focus); + SendMessage(std::move(message)); + + SetFormFieldInFocus(in_focus); +} + SkColor PdfViewPluginBase::GetBackgroundColor() { return background_color_; } +void PdfViewPluginBase::SetIsSelecting(bool is_selecting) { + base::Value message(base::Value::Type::DICTIONARY); + message.SetStringKey("type", "setIsSelecting"); + message.SetBoolKey("isSelecting", is_selecting); + SendMessage(std::move(message)); +} + +void PdfViewPluginBase::DocumentFocusChanged(bool document_has_focus) { + base::Value message(base::Value::Type::DICTIONARY); + message.SetStringKey("type", "documentFocusChanged"); + message.SetBoolKey("hasFocus", document_has_focus); + SendMessage(std::move(message)); +} + void PdfViewPluginBase::HandleMessage(const base::Value& message) { using MessageHandler = void (PdfViewPluginBase::*)(const base::Value&); static constexpr auto kMessageHandlers = @@ -108,7 +371,10 @@ void PdfViewPluginBase::HandleMessage(const base::Value& message) { &PdfViewPluginBase::HandleDisplayAnnotationsMessage}, {"getNamedDestination", &PdfViewPluginBase::HandleGetNamedDestinationMessage}, + {"getPasswordComplete", + &PdfViewPluginBase::HandleGetPasswordCompleteMessage}, {"getSelectedText", &PdfViewPluginBase::HandleGetSelectedTextMessage}, + {"getThumbnail", &PdfViewPluginBase::HandleGetThumbnailMessage}, {"rotateClockwise", &PdfViewPluginBase::HandleRotateClockwiseMessage}, {"rotateCounterclockwise", &PdfViewPluginBase::HandleRotateCounterclockwiseMessage}, @@ -117,6 +383,8 @@ void PdfViewPluginBase::HandleMessage(const base::Value& message) { &PdfViewPluginBase::HandleSetBackgroundColorMessage}, {"setReadOnly", &PdfViewPluginBase::HandleSetReadOnlyMessage}, {"setTwoUpView", &PdfViewPluginBase::HandleSetTwoUpViewMessage}, + {"stopScrolling", &PdfViewPluginBase::HandleStopScrollingMessage}, + {"updateScroll", &PdfViewPluginBase::HandleUpdateScrollMessage}, {"viewport", &PdfViewPluginBase::HandleViewportMessage}, }); @@ -135,6 +403,58 @@ void PdfViewPluginBase::HandleMessage(const base::Value& message) { (this->*handler)(message); } +void PdfViewPluginBase::SaveToBuffer(const std::string& token) { + engine()->KillFormFocus(); + + base::Value message(base::Value::Type::DICTIONARY); + message.SetStringKey("type", "saveData"); + message.SetStringKey("token", token); + message.SetStringKey("fileName", GetFileNameForSaveFromUrl(url_)); + + base::Value data_to_save; + if (edit_mode_) { + base::Value::BlobStorage data = engine()->GetSaveData(); + if (IsSaveDataSizeValid(data.size())) + data_to_save = base::Value(std::move(data)); + } else { +#if BUILDFLAG(IS_CHROMEOS_ASH) + uint32_t length = engine()->GetLoadedByteSize(); + if (IsSaveDataSizeValid(length)) { + base::Value::BlobStorage data(length); + if (engine()->ReadLoadedBytes(length, data.data())) + data_to_save = base::Value(std::move(data)); + } +#else + NOTREACHED(); +#endif // BUILDFLAG(IS_CHROMEOS_ASH) + } + + message.SetKey("dataToSave", std::move(data_to_save)); + SendMessage(std::move(message)); +} + +void PdfViewPluginBase::ConsumeSaveToken(const std::string& token) { + base::Value message(base::Value::Type::DICTIONARY); + message.SetStringKey("type", "consumeSaveToken"); + message.SetStringKey("token", token); + SendMessage(std::move(message)); +} + +void PdfViewPluginBase::SendLoadingProgress(double percentage) { + DCHECK(percentage == -1 || (percentage >= 0 && percentage <= 100)); + + base::Value message(base::Value::Type::DICTIONARY); + message.SetStringKey("type", "loadProgress"); + message.SetDoubleKey("progress", percentage); + SendMessage(std::move(message)); +} + +void PdfViewPluginBase::SendPrintPreviewLoadedNotification() { + base::Value message(base::Value::Type::DICTIONARY); + message.SetStringKey("type", "printPreviewLoaded"); + SendMessage(std::move(message)); +} + void PdfViewPluginBase::OnPaint(const std::vector& paint_rects, std::vector& ready, std::vector& pending) { @@ -187,10 +507,10 @@ void PdfViewPluginBase::InvalidateAfterPaintDone() { return; ScheduleTaskOnMainThread( - base::TimeDelta(), + FROM_HERE, base::BindOnce(&PdfViewPluginBase::ClearDeferredInvalidates, GetWeakPtr()), - 0); + /*result=*/0, base::TimeDelta()); } void PdfViewPluginBase::OnGeometryChanged(double old_zoom, @@ -204,26 +524,25 @@ void PdfViewPluginBase::OnGeometryChanged(double old_zoom, void PdfViewPluginBase::UpdateGeometryOnViewChanged( const gfx::Rect& new_view_rect, float new_device_scale) { - const gfx::Size view_device_size(new_view_rect.width() * new_device_scale, - new_view_rect.height() * new_device_scale); + DCHECK_GT(new_device_scale, 0.0f); + const gfx::Rect new_plugin_rect = + gfx::ScaleToEnclosingRectSafe(new_view_rect, new_device_scale); - if (view_device_size == plugin_size_ && new_device_scale == device_scale_ && - new_view_rect.origin() == plugin_offset_) { + if (new_device_scale == device_scale_ && new_plugin_rect == plugin_rect_) { return; } const float old_device_scale = device_scale_; device_scale_ = new_device_scale; + plugin_rect_ = new_plugin_rect; plugin_dip_size_ = new_view_rect.size(); - plugin_size_ = view_device_size; - plugin_offset_ = new_view_rect.origin(); - paint_manager().SetSize(plugin_size_, device_scale_); + paint_manager().SetSize(plugin_rect_.size(), device_scale_); // Initialize the image data buffer if the context size changes. const gfx::Size old_image_size = gfx::SkISizeToSize(image_data_.dimensions()); const gfx::Size new_image_size = - PaintManager::GetNewContextSize(old_image_size, plugin_size_); + PaintManager::GetNewContextSize(old_image_size, plugin_rect_.size()); if (new_image_size != old_image_size) { InitImageData(new_image_size); first_paint_ = true; @@ -231,7 +550,7 @@ void PdfViewPluginBase::UpdateGeometryOnViewChanged( // Skip updating the geometry if the new image data buffer is empty. if (image_data_.drawsNothing()) { - DCHECK(plugin_size_.IsEmpty()); + DCHECK(plugin_rect_.IsEmpty()); return; } @@ -247,18 +566,18 @@ void PdfViewPluginBase::RecalculateAreas(double old_zoom, if (zoom_ != old_zoom || device_scale_ != old_device_scale) engine()->ZoomUpdated(zoom_ * device_scale_); - available_area_ = gfx::Rect(plugin_size_); + available_area_ = gfx::Rect(plugin_rect_.size()); int doc_width = GetDocumentPixelWidth(); if (doc_width < available_area_.width()) { // Center the document horizontally inside the plugin rectangle. - available_area_.Offset((plugin_size_.width() - doc_width) / 2, 0); + available_area_.Offset((plugin_rect_.width() - doc_width) / 2, 0); available_area_.set_width(doc_width); } // The distance between top of the plugin and the bottom of the document in // pixels. int bottom_of_document = GetDocumentPixelHeight(); - if (bottom_of_document < plugin_size_.height()) + if (bottom_of_document < plugin_rect_.height()) available_area_.set_height(bottom_of_document); CalculateBackgroundParts(); @@ -268,15 +587,15 @@ void PdfViewPluginBase::RecalculateAreas(double old_zoom, if (document_size_.IsEmpty()) return; - paint_manager_.InvalidateRect(gfx::Rect(plugin_size_)); + paint_manager_.InvalidateRect(gfx::Rect(plugin_rect_.size())); } void PdfViewPluginBase::CalculateBackgroundParts() { background_parts_.clear(); int left_width = available_area_.x(); int right_start = available_area_.right(); - int right_width = std::abs(plugin_size().width() - available_area_.right()); - int bottom = std::min(available_area_.bottom(), plugin_size().height()); + int right_width = std::abs(plugin_rect_.width() - available_area_.right()); + int bottom = std::min(available_area_.bottom(), plugin_rect_.height()); // Note: we assume the display of the PDF document is always centered // horizontally, but not necessarily centered vertically. @@ -291,12 +610,21 @@ void PdfViewPluginBase::CalculateBackgroundParts() { background_parts_.push_back(part); // Add the bottom rectangle. - part.location = gfx::Rect(0, bottom, plugin_size().width(), - plugin_size().height() - bottom); + part.location = gfx::Rect(0, bottom, plugin_rect_.width(), + plugin_rect_.height() - bottom); if (!part.location.IsEmpty()) background_parts_.push_back(part); } +void PdfViewPluginBase::UpdateScroll() { + DCHECK(!stop_scrolling_); + const gfx::PointF scaled_scroll_position = gfx::ScalePoint( + BoundScrollPositionToDocument(gfx::PointF(scroll_position_)), + device_scale_); + engine()->ScrolledToXPosition(scaled_scroll_position.x()); + engine()->ScrolledToYPosition(scaled_scroll_position.y()); +} + gfx::PointF PdfViewPluginBase::BoundScrollPositionToDocument( const gfx::PointF& scroll_position) { float max_x = std::max( @@ -318,36 +646,6 @@ int PdfViewPluginBase::GetDocumentPixelHeight() const { std::ceil(document_size_.height() * zoom() * device_scale())); } -void PdfViewPluginBase::LoadAccessibility() { - accessibility_state_ = AccessibilityState::kLoaded; - AccessibilityDocInfo doc_info; - doc_info.page_count = engine_->GetNumberOfPages(); - doc_info.text_accessible = - engine_->HasPermission(PDFEngine::PERMISSION_COPY_ACCESSIBLE); - doc_info.text_copyable = engine_->HasPermission(PDFEngine::PERMISSION_COPY); - - // A new document layout will trigger the creation of a new accessibility - // tree, so |next_accessibility_page_index_| should be reset to ignore - // outdated asynchronous calls of PrepareAndSetAccessibilityPageInfo(). - next_accessibility_page_index_ = 0; - SetAccessibilityDocInfo(doc_info); - - // If the document contents isn't accessible, don't send anything more. - if (!(engine_->HasPermission(PDFEngine::PERMISSION_COPY) || - engine_->HasPermission(PDFEngine::PERMISSION_COPY_ACCESSIBLE))) { - return; - } - - PrepareAndSetAccessibilityViewportInfo(); - - // Schedule loading the first page. - ScheduleTaskOnMainThread( - kAccessibilityPageDelay, - base::BindOnce(&PdfViewPluginBase::PrepareAndSetAccessibilityPageInfo, - GetWeakPtr()), - 0); -} - void PdfViewPluginBase::PrepareAndSetAccessibilityPageInfo(int32_t page_index) { // Outdated calls are ignored. if (page_index != next_accessibility_page_index_) @@ -368,15 +666,16 @@ void PdfViewPluginBase::PrepareAndSetAccessibilityPageInfo(int32_t page_index) { // Schedule loading the next page. ScheduleTaskOnMainThread( - kAccessibilityPageDelay, + FROM_HERE, base::BindOnce(&PdfViewPluginBase::PrepareAndSetAccessibilityPageInfo, GetWeakPtr()), - page_index + 1); + /*result=*/page_index + 1, kAccessibilityPageDelay); } void PdfViewPluginBase::PrepareAndSetAccessibilityViewportInfo() { AccessibilityViewportInfo viewport_info; - viewport_info.scroll = gfx::ScaleToFlooredPoint(plugin_offset_, -1); + viewport_info.scroll = + gfx::ScaleToFlooredPoint(plugin_rect_.origin(), -1 / device_scale_); viewport_info.offset = gfx::ScaleToFlooredPoint(available_area_.origin(), 1 / (device_scale_ * zoom_)); viewport_info.zoom = zoom_; @@ -434,6 +733,14 @@ void PdfViewPluginBase::HandleGetNamedDestinationMessage( SendMessage(std::move(reply)); } +void PdfViewPluginBase::HandleGetPasswordCompleteMessage( + const base::Value& message) { + const std::string* password = message.FindStringKey("password"); + CHECK(password); + DCHECK(!password_callback_.is_null()); + std::move(password_callback_).Run(*password); +} + void PdfViewPluginBase::HandleGetSelectedTextMessage( const base::Value& message) { // Always return unix newlines to JavaScript. @@ -445,6 +752,15 @@ void PdfViewPluginBase::HandleGetSelectedTextMessage( SendMessage(std::move(reply)); } +void PdfViewPluginBase::HandleGetThumbnailMessage(const base::Value& message) { + const int page_index = message.FindIntKey("page").value(); + base::Value reply = PrepareReplyMessage("getThumbnailReply", message); + + engine()->RequestThumbnail(page_index, device_scale_, + base::BindOnce(&PdfViewPluginBase::SendThumbnail, + GetWeakPtr(), std::move(reply))); +} + void PdfViewPluginBase::HandleRotateClockwiseMessage( const base::Value& /*message*/) { engine()->RotateClockwise(); @@ -475,6 +791,21 @@ void PdfViewPluginBase::HandleSetTwoUpViewMessage(const base::Value& message) { engine()->SetTwoUpView(message.FindBoolKey("enableTwoUpView").value()); } +void PdfViewPluginBase::HandleStopScrollingMessage( + const base::Value& /*message*/) { + stop_scrolling_ = true; +} + +void PdfViewPluginBase::HandleUpdateScrollMessage(const base::Value& message) { + if (stop_scrolling_) + return; + + scroll_position_ = + gfx::Point(base::checked_cast(message.FindDoubleKey("x").value()), + base::checked_cast(message.FindDoubleKey("y").value())); + UpdateScroll(); +} + void PdfViewPluginBase::HandleViewportMessage(const base::Value& message) { const base::Value* layout_options_value = message.FindDictKey("layoutOptions"); @@ -529,7 +860,7 @@ void PdfViewPluginBase::HandleViewportMessage(const base::Value& message) { // position on screen of the paint. gfx::Vector2d paint_offset; - if (plugin_size_.width() > GetDocumentPixelWidth() * zoom_ratio) { + if (plugin_rect_.width() > GetDocumentPixelWidth() * zoom_ratio) { // We want to keep the paint in the middle but it must stay in the same // position relative to the scroll bars. paint_offset = gfx::Vector2d(0, (1 - zoom_ratio) * pinch_center.y()); @@ -542,10 +873,10 @@ void PdfViewPluginBase::HandleViewportMessage(const base::Value& message) { } else if (last_bitmap_smaller_) { // When the document width covers the display area's width, we will anchor // the scroll bars disregarding where the actual pinch certer is. - pinch_center = gfx::Point((plugin_size_.width() / device_scale_) / 2, - (plugin_size_.height() / device_scale_) / 2); + pinch_center = gfx::Point((plugin_rect_.width() / device_scale_) / 2, + (plugin_rect_.height() / device_scale_) / 2); const double zoom_when_doc_covers_plugin_width = - zoom_ * plugin_size_.width() / GetDocumentPixelWidth(); + zoom_ * plugin_rect_.width() / GetDocumentPixelWidth(); paint_offset = gfx::Vector2d( (1 - new_zoom / zoom_when_doc_covers_plugin_width) * pinch_center.x(), (1 - zoom_ratio) * pinch_center.y()); @@ -594,7 +925,7 @@ void PdfViewPluginBase::DoPaint(const std::vector& paint_rects, std::vector& ready, std::vector& pending) { if (image_data_.drawsNothing()) { - DCHECK(plugin_size_.IsEmpty()); + DCHECK(plugin_rect_.IsEmpty()); return; } @@ -608,7 +939,8 @@ void PdfViewPluginBase::DoPaint(const std::vector& paint_rects, for (const gfx::Rect& paint_rect : paint_rects) { // Intersect with plugin area since there could be pending invalidates from // when the plugin area was larger. - gfx::Rect rect = gfx::IntersectRects(paint_rect, gfx::Rect(plugin_size_)); + gfx::Rect rect = + gfx::IntersectRects(paint_rect, gfx::Rect(plugin_rect_.size())); if (rect.IsEmpty()) continue; @@ -636,7 +968,7 @@ void PdfViewPluginBase::DoPaint(const std::vector& paint_rects, : engine()->GetPageScreenRect(0).y(); if (rect.y() < first_page_ypos) { gfx::Rect region = gfx::IntersectRects( - rect, gfx::Rect(gfx::Size(plugin_size_.width(), first_page_ypos))); + rect, gfx::Rect(gfx::Size(plugin_rect_.width(), first_page_ypos))); ready.push_back(PaintReadyRect(region, GetPluginImageData())); image_data_.erase(background_color_, gfx::RectToSkIRect(region)); } @@ -679,4 +1011,189 @@ void PdfViewPluginBase::ClearDeferredInvalidates( deferred_invalidates_.clear(); } +void PdfViewPluginBase::SendAttachments() { + const std::vector& attachment_infos = + engine()->GetDocumentAttachmentInfoList(); + if (attachment_infos.empty()) + return; + + base::Value attachments(base::Value::Type::LIST); + for (const DocumentAttachmentInfo& attachment_info : attachment_infos) { + // Send `size` as -1 to indicate that the attachment is too large to be + // downloaded. + const int size = attachment_info.size_bytes <= kMaximumSavedFileSize + ? static_cast(attachment_info.size_bytes) + : -1; + + base::Value attachment(base::Value::Type::DICTIONARY); + attachment.SetStringKey("name", attachment_info.name); + attachment.SetIntKey("size", size); + attachment.SetBoolKey("readable", attachment_info.is_readable); + attachments.Append(std::move(attachment)); + } + + base::Value message(base::Value::Type::DICTIONARY); + message.SetStringKey("type", "attachments"); + message.SetKey("attachmentsData", std::move(attachments)); + SendMessage(std::move(message)); +} + +void PdfViewPluginBase::SendBookmarks() { + base::Value bookmarks = engine()->GetBookmarks(); + if (bookmarks.GetList().empty()) + return; + + base::Value message(base::Value::Type::DICTIONARY); + message.SetStringKey("type", "bookmarks"); + message.SetKey("bookmarksData", std::move(bookmarks)); + SendMessage(std::move(message)); +} + +void PdfViewPluginBase::SendMetadata() { + base::Value metadata(base::Value::Type::DICTIONARY); + const DocumentMetadata& document_metadata = engine()->GetDocumentMetadata(); + + const std::string version = FormatPdfVersion(document_metadata.version); + if (!version.empty()) + metadata.SetStringKey("version", version); + + metadata.SetStringKey("fileSize", + ui::FormatBytes(document_metadata.size_bytes)); + + metadata.SetBoolKey("linearized", document_metadata.linearized); + + if (!document_metadata.title.empty()) + metadata.SetStringKey("title", document_metadata.title); + + if (!document_metadata.author.empty()) + metadata.SetStringKey("author", document_metadata.author); + + if (!document_metadata.subject.empty()) + metadata.SetStringKey("subject", document_metadata.subject); + + if (!document_metadata.keywords.empty()) + metadata.SetStringKey("keywords", document_metadata.keywords); + + if (!document_metadata.creator.empty()) + metadata.SetStringKey("creator", document_metadata.creator); + + if (!document_metadata.producer.empty()) + metadata.SetStringKey("producer", document_metadata.producer); + + if (!document_metadata.creation_date.is_null()) { + metadata.SetStringKey("creationDate", base::TimeFormatShortDateAndTime( + document_metadata.creation_date)); + } + + if (!document_metadata.mod_date.is_null()) { + metadata.SetStringKey("modDate", base::TimeFormatShortDateAndTime( + document_metadata.mod_date)); + } + + metadata.SetStringKey("pageSize", + FormatPageSize(engine()->GetUniformPageSizePoints())); + + metadata.SetBoolKey("canSerializeDocument", + IsSaveDataSizeValid(engine()->GetLoadedByteSize())); + + base::Value message(base::Value::Type::DICTIONARY); + message.SetStringKey("type", "metadata"); + message.SetKey("metadataData", std::move(metadata)); + SendMessage(std::move(message)); +} + +void PdfViewPluginBase::SendThumbnail(base::Value reply, Thumbnail thumbnail) { + const SkBitmap& bitmap = thumbnail.bitmap(); + base::Value image_data(base::make_span( + static_cast(bitmap.getPixels()), bitmap.computeByteSize())); + + DCHECK_EQ(*reply.FindStringKey("type"), "getThumbnailReply"); + DCHECK(reply.FindStringKey("messageId")); + reply.SetKey("imageData", std::move(image_data)); + reply.SetIntKey("width", bitmap.width()); + reply.SetIntKey("height", bitmap.height()); + SendMessage(std::move(reply)); +} + +void PdfViewPluginBase::LoadAccessibility() { + accessibility_state_ = AccessibilityState::kLoaded; + AccessibilityDocInfo doc_info; + doc_info.page_count = engine_->GetNumberOfPages(); + doc_info.text_accessible = + engine_->HasPermission(PDFEngine::PERMISSION_COPY_ACCESSIBLE); + doc_info.text_copyable = engine_->HasPermission(PDFEngine::PERMISSION_COPY); + + // A new document layout will trigger the creation of a new accessibility + // tree, so `next_accessibility_page_index_` should be reset to ignore + // outdated asynchronous calls of PrepareAndSetAccessibilityPageInfo(). + next_accessibility_page_index_ = 0; + SetAccessibilityDocInfo(doc_info); + + // If the document contents isn't accessible, don't send anything more. + if (!(engine_->HasPermission(PDFEngine::PERMISSION_COPY) || + engine_->HasPermission(PDFEngine::PERMISSION_COPY_ACCESSIBLE))) { + return; + } + + PrepareAndSetAccessibilityViewportInfo(); + + // Schedule loading the first page. + ScheduleTaskOnMainThread( + FROM_HERE, + base::BindOnce(&PdfViewPluginBase::PrepareAndSetAccessibilityPageInfo, + GetWeakPtr()), + /*result=*/0, kAccessibilityPageDelay); +} + +namespace { + +// These values are persisted to logs. Entries should not be renumbered and +// numeric values should never be reused. +enum class PdfHasAttachment { + kNo = 0, + kYes = 1, + kMaxValue = kYes, +}; + +// These values are persisted to logs. Entries should not be renumbered and +// numeric values should never be reused. +enum class PdfIsTagged { + kNo = 0, + kYes = 1, + kMaxValue = kYes, +}; + +} // namespace + +void PdfViewPluginBase::RecordDocumentMetrics() { + const DocumentMetadata& document_metadata = engine()->GetDocumentMetadata(); + HistogramEnumeration("PDF.Version", document_metadata.version); + HistogramCustomCounts("PDF.PageCount", document_metadata.page_count, 1, + 1000000, 50); + HistogramEnumeration("PDF.HasAttachment", document_metadata.has_attachments + ? PdfHasAttachment::kYes + : PdfHasAttachment::kNo); + HistogramEnumeration("PDF.IsTagged", document_metadata.tagged + ? PdfIsTagged::kYes + : PdfIsTagged::kNo); + HistogramEnumeration("PDF.FormType", document_metadata.form_type); +} + +template +void PdfViewPluginBase::HistogramEnumeration(const char* name, T sample) { + if (IsPrintPreview()) + return; + base::UmaHistogramEnumeration(name, sample); +} + +void PdfViewPluginBase::HistogramCustomCounts(const char* name, + int32_t sample, + int32_t min, + int32_t max, + uint32_t bucket_count) { + if (IsPrintPreview()) + return; + base::UmaHistogramCustomCounts(name, sample, min, max, bucket_count); +} + } // namespace chrome_pdf diff --git a/chromium/pdf/pdf_view_plugin_base.h b/chromium/pdf/pdf_view_plugin_base.h index 93d416ff6a0..54d3b6bed1a 100644 --- a/chromium/pdf/pdf_view_plugin_base.h +++ b/chromium/pdf/pdf_view_plugin_base.h @@ -11,6 +11,7 @@ #include #include +#include "base/callback.h" #include "base/memory/weak_ptr.h" #include "pdf/paint_manager.h" #include "pdf/pdf_engine.h" @@ -29,6 +30,7 @@ namespace chrome_pdf { class Image; class PDFiumEngine; +class Thumbnail; class UrlLoader; struct AccessibilityActionData; struct AccessibilityCharInfo; @@ -49,8 +51,37 @@ class PdfViewPluginBase : public PDFEngine::Client, PdfViewPluginBase& operator=(const PdfViewPluginBase& other) = delete; // PDFEngine::Client: + void ProposeDocumentLayout(const DocumentLayout& layout) override; void Invalidate(const gfx::Rect& rect) override; + void DidScroll(const gfx::Vector2d& offset) override; + void ScrollToX(int x_screen_coords) override; + void ScrollToY(int y_screen_coords) override; + void ScrollBy(const gfx::Vector2d& delta) override; + void ScrollToPage(int page) override; + void NavigateTo(const std::string& url, + WindowOpenDisposition disposition) override; + void NavigateToDestination(int page, + const float* x, + const float* y, + const float* zoom) override; + void NotifyTouchSelectionOccurred() override; + void GetDocumentPassword( + base::OnceCallback callback) override; + void Beep() override; + std::string GetURL() override; + void Email(const std::string& to, + const std::string& cc, + const std::string& bcc, + const std::string& subject, + const std::string& body) override; + std::unique_ptr CreateUrlLoader() override; + void DocumentLoadComplete() override; + void DocumentLoadFailed() override; + void DocumentLoadProgress(uint32_t available, uint32_t doc_size) override; + void FormTextFieldFocusChange(bool in_focus) override; SkColor GetBackgroundColor() override; + void SetIsSelecting(bool is_selecting) override; + void DocumentFocusChanged(bool document_has_focus) override; // PaintManager::Client void OnPaint(const std::vector& paint_rects, @@ -64,6 +95,10 @@ class PdfViewPluginBase : public PDFEngine::Client, void HandleAccessibilityAction(const AccessibilityActionData& action_data); protected: + // Do not save files with over 100 MB. This cap should be kept in sync with + // and is also enforced in chrome/browser/resources/pdf/pdf_viewer.js. + static constexpr size_t kMaximumSavedFileSize = 100 * 1000 * 1000; + enum class AccessibilityState { kOff = 0, // Off. kPending, // Enabled but waiting for doc to load. @@ -121,6 +156,18 @@ class PdfViewPluginBase : public PDFEngine::Client, // non-blocking. virtual void SendMessage(base::Value message) = 0; + void SaveToBuffer(const std::string& token); + + // Consumes a token for saving the document. + void ConsumeSaveToken(const std::string& token); + + // Sends the loading progress, where `percentage` represents the progress, or + // -1 for loading error. + void SendLoadingProgress(double percentage); + + // Send a notification that the print preview has loaded. + void SendPrintPreviewLoadedNotification(); + // Initialize image buffer(s) according to the new context size. virtual void InitImageData(const gfx::Size& size) = 0; @@ -147,6 +194,9 @@ class PdfViewPluginBase : public PDFEngine::Client, // aren't painted by the PDF engine). void CalculateBackgroundParts(); + // Repaints the plugin contents based on the current scroll position. + void UpdateScroll(); + // Bound the given scroll position to the document. gfx::PointF BoundScrollPositionToDocument(const gfx::PointF& scroll_position); @@ -155,14 +205,14 @@ class PdfViewPluginBase : public PDFEngine::Client, int GetDocumentPixelWidth() const; int GetDocumentPixelHeight() const; - // Starts loading accessibility information. - void LoadAccessibility(); + // Sets the text input type for this plugin based on `in_focus`. + virtual void SetFormFieldInFocus(bool in_focus) = 0; // Sets the accessibility information about the PDF document in the renderer. virtual void SetAccessibilityDocInfo( const AccessibilityDocInfo& doc_info) = 0; - // Sets the accessibility information about the given |page_index| in the + // Sets the accessibility information about the given `page_index` in the // renderer. void PrepareAndSetAccessibilityPageInfo(int32_t page_index); @@ -184,16 +234,39 @@ class PdfViewPluginBase : public PDFEngine::Client, virtual void SetAccessibilityViewportInfo( const AccessibilityViewportInfo& viewport_info) = 0; - const SkBitmap& image_data() const { return image_data_; } + static constexpr bool IsSaveDataSizeValid(size_t size) { + return size > 0 && size <= kMaximumSavedFileSize; + } + + // Disables browser commands because of restrictions on how the data is to be + // used (i.e. can't copy/print). `content_restrictions` should have its bits + // set by `chrome_pdf::ContentRestriction` enum values. + virtual void SetContentRestrictions(int content_restrictions) = 0; + + // Sends start/stop loading notifications to the plugin's render frame. + // TODO(crbug.com/702993): Evaluate whether these methods are needed when the + // plugin is moved into a renderer process. + virtual void DidStartLoading() = 0; + virtual void DidStopLoading() = 0; + + // Performs tasks necessary when the document is loaded in print preview mode. + virtual void OnPrintPreviewLoaded() = 0; + + // Records user actions. + virtual void UserMetricsRecordAction(const std::string& action) = 0; + + void set_url(const std::string& url) { url_ = url; } + + bool full_frame() const { return full_frame_; } + void set_full_frame(bool full_frame) { full_frame_ = full_frame; } + SkBitmap& mutable_image_data() { return image_data_; } const gfx::Rect& available_area() const { return available_area_; } void set_document_size(const gfx::Size& size) { document_size_ = size; } - const gfx::Size& plugin_size() const { return plugin_size_; } - - const gfx::Point& plugin_offset() const { return plugin_offset_; } + const gfx::Rect& plugin_rect() const { return plugin_rect_; } void SetBackgroundColor(SkColor background_color) { background_color_ = background_color; @@ -206,29 +279,39 @@ class PdfViewPluginBase : public PDFEngine::Client, float device_scale() const { return device_scale_; } - bool stop_scrolling() const { return stop_scrolling_; } - void set_stop_scrolling(bool stop_scrolling) { - stop_scrolling_ = stop_scrolling; + void set_scroll_position(const gfx::Point& scroll_position) { + scroll_position_ = scroll_position; } - DocumentLoadState document_load_state() { return document_load_state_; } + bool stop_scrolling() const { return stop_scrolling_; } + + DocumentLoadState document_load_state() const { return document_load_state_; } void set_document_load_state(DocumentLoadState state) { document_load_state_ = state; } - AccessibilityState accessibility_state() { return accessibility_state_; } + AccessibilityState accessibility_state() const { + return accessibility_state_; + } + + bool edit_mode() const { return edit_mode_; } + void set_edit_mode(bool edit_mode) { edit_mode_ = edit_mode; } private: // Message handlers. void HandleDisplayAnnotationsMessage(const base::Value& message); void HandleGetNamedDestinationMessage(const base::Value& message); + void HandleGetPasswordCompleteMessage(const base::Value& message); void HandleGetSelectedTextMessage(const base::Value& message); + void HandleGetThumbnailMessage(const base::Value& message); void HandleRotateClockwiseMessage(const base::Value& /*message*/); void HandleRotateCounterclockwiseMessage(const base::Value& /*message*/); void HandleSelectAllMessage(const base::Value& /*message*/); void HandleSetBackgroundColorMessage(const base::Value& message); void HandleSetReadOnlyMessage(const base::Value& message); void HandleSetTwoUpViewMessage(const base::Value& message); + void HandleStopScrollingMessage(const base::Value& /*message*/); + void HandleUpdateScrollMessage(const base::Value& message); void HandleViewportMessage(const base::Value& message); // Paints the given invalid area of the plugin to the given graphics device. @@ -244,9 +327,46 @@ class PdfViewPluginBase : public PDFEngine::Client, // Callback to clear deferred invalidates after painting finishes. void ClearDeferredInvalidates(int32_t /*unused_but_required*/); + // Sends the attachments data. + void SendAttachments(); + + // Sends the bookmarks data. + void SendBookmarks(); + + // Send document metadata data. + void SendMetadata(); + + // Sends the thumbnail image data. + void SendThumbnail(base::Value reply, Thumbnail thumbnail); + + // Starts loading accessibility information. + void LoadAccessibility(); + + // Records metrics about the document metadata. + void RecordDocumentMetrics(); + + // Adds a sample to an enumerated histogram and filter out print preview + // usage. + template + void HistogramEnumeration(const char* name, T sample); + + // Adds a sample to a custom counts histogram and filter out print preview + // usage. + void HistogramCustomCounts(const char* name, + int32_t sample, + int32_t min, + int32_t max, + uint32_t bucket_count); + std::unique_ptr engine_; PaintManager paint_manager_{this}; + // The URL of the PDF document. + std::string url_; + + // True if the plugin occupies the entire frame (not embedded). + bool full_frame_ = false; + // Image data buffer for painting. SkBitmap image_data_; @@ -263,14 +383,11 @@ class PdfViewPluginBase : public PDFEngine::Client, // high and there are 10 pages, the height will be 8000). gfx::Size document_size_; - // Size, in pixels, of plugin rectangle. - gfx::Size plugin_size_; - // Size, in DIPs, of plugin rectangle. gfx::Size plugin_dip_size_; - // Positional offset, in CSS pixels, of the plugin rectangle. - gfx::Point plugin_offset_; + // The plugin rectangle in device pixels. + gfx::Rect plugin_rect_; // The background color of the PDF viewer. SkColor background_color_ = SK_ColorTRANSPARENT; @@ -295,6 +412,9 @@ class PdfViewPluginBase : public PDFEngine::Client, // True if we request a new bitmap rendering. bool needs_reraster_ = true; + // The scroll position in CSS pixels. + gfx::Point scroll_position_; + // The scroll position for the last raster, before any transformations are // applied. gfx::PointF scroll_position_at_last_raster_; @@ -309,6 +429,12 @@ class PdfViewPluginBase : public PDFEngine::Client, // be painted until this is received. bool received_viewport_message_ = false; + // The callback for receiving the password from the page. + base::OnceCallback password_callback_; + + // The last document load progress value sent to the web page. + double last_progress_sent_ = 0.0; + // The current state of document load. DocumentLoadState document_load_state_ = DocumentLoadState::kLoading; @@ -318,6 +444,9 @@ class PdfViewPluginBase : public PDFEngine::Client, // The next accessibility page index, used to track interprocess calls when // reconstructing the tree for new document layouts. int32_t next_accessibility_page_index_ = 0; + + // Whether the document is in edit mode. + bool edit_mode_ = false; }; } // namespace chrome_pdf diff --git a/chromium/pdf/pdf_view_plugin_base_unittest.cc b/chromium/pdf/pdf_view_plugin_base_unittest.cc new file mode 100644 index 00000000000..d7c8b943d92 --- /dev/null +++ b/chromium/pdf/pdf_view_plugin_base_unittest.cc @@ -0,0 +1,161 @@ +// Copyright 2021 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/pdf_view_plugin_base.h" + +#include +#include +#include +#include + +#include "base/memory/weak_ptr.h" +#include "base/time/time.h" +#include "base/values.h" +#include "pdf/accessibility_structs.h" +#include "pdf/pdfium/pdfium_engine.h" +#include "pdf/ppapi_migration/callback.h" +#include "pdf/ppapi_migration/graphics.h" +#include "pdf/ppapi_migration/url_loader.h" +#include "ppapi/cpp/instance.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/skia/include/core/SkColor.h" +#include "ui/gfx/geometry/size.h" + +namespace chrome_pdf { + +namespace { + +// This test approach relies on PdfViewPluginBase continuing to exist. +// PdfViewPluginBase and PdfViewWebPlugin are going to merge once +// OutOfProcessInstance is deprecated. +class FakePdfViewPluginBase : public PdfViewPluginBase { + public: + // Public for testing. + using PdfViewPluginBase::ConsumeSaveToken; + using PdfViewPluginBase::HandleMessage; + + MOCK_METHOD(bool, Confirm, (const std::string&), (override)); + + MOCK_METHOD(std::string, + Prompt, + (const std::string&, const std::string&), + (override)); + + MOCK_METHOD(std::unique_ptr, CreateUrlLoader, (), (override)); + + MOCK_METHOD(std::vector, + SearchString, + (const char16_t*, const char16_t*, bool), + (override)); + + MOCK_METHOD(pp::Instance*, GetPluginInstance, (), (override)); + + MOCK_METHOD(bool, IsPrintPreview, (), (override)); + + MOCK_METHOD(void, SetSelectedText, (const std::string&), (override)); + + MOCK_METHOD(void, SetLinkUnderCursor, (const std::string&), (override)); + + MOCK_METHOD(bool, IsValidLink, (const std::string&), (override)); + + MOCK_METHOD(std::unique_ptr, + CreatePaintGraphics, + (const gfx::Size&), + (override)); + + MOCK_METHOD(bool, BindPaintGraphics, (Graphics&), (override)); + + MOCK_METHOD(void, + ScheduleTaskOnMainThread, + (const base::Location&, ResultCallback, int32_t, base::TimeDelta), + (override)); + + MOCK_METHOD(base::WeakPtr, GetWeakPtr, (), (override)); + + MOCK_METHOD(std::unique_ptr, + CreateUrlLoaderInternal, + (), + (override)); + + MOCK_METHOD(void, DidOpen, (std::unique_ptr, int32_t), (override)); + + MOCK_METHOD(void, + DidOpenPreview, + (std::unique_ptr, int32_t), + (override)); + + void SendMessage(base::Value message) override { + sent_message_ = std::move(message); + } + + MOCK_METHOD(void, InitImageData, (const gfx::Size&), (override)); + + MOCK_METHOD(void, SetFormFieldInFocus, (bool in_focus), (override)); + + MOCK_METHOD(void, + SetAccessibilityDocInfo, + (const AccessibilityDocInfo&), + (override)); + + MOCK_METHOD(void, + SetAccessibilityPageInfo, + (AccessibilityPageInfo, + std::vector, + std::vector, + AccessibilityPageObjects), + (override)); + + MOCK_METHOD(void, + SetAccessibilityViewportInfo, + (const AccessibilityViewportInfo&), + (override)); + + MOCK_METHOD(void, SetContentRestrictions, (int), (override)); + + MOCK_METHOD(void, DidStartLoading, (), (override)); + + MOCK_METHOD(void, DidStopLoading, (), (override)); + + MOCK_METHOD(void, OnPrintPreviewLoaded, (), (override)); + + MOCK_METHOD(void, UserMetricsRecordAction, (const std::string&), (override)); + + const base::Value& sent_message() const { return sent_message_; } + + private: + base::Value sent_message_; +}; + +} // namespace + +class PdfViewPluginBaseTest : public testing::Test { + protected: + FakePdfViewPluginBase fake_plugin_; +}; + +TEST_F(PdfViewPluginBaseTest, ConsumeSaveToken) { + const std::string kTokenString("12345678901234567890"); + fake_plugin_.ConsumeSaveToken(kTokenString); + + base::Value expected_message(base::Value::Type::DICTIONARY); + expected_message.SetStringKey("type", "consumeSaveToken"); + expected_message.SetStringKey("token", kTokenString); + + EXPECT_EQ(expected_message, fake_plugin_.sent_message()); +} + +TEST_F(PdfViewPluginBaseTest, HandleSetBackgroundColorMessage) { + const SkColor kNewBackgroundColor = SK_ColorGREEN; + ASSERT_NE(kNewBackgroundColor, fake_plugin_.GetBackgroundColor()); + + base::Value message(base::Value::Type::DICTIONARY); + message.SetStringKey("type", "setBackgroundColor"); + message.SetDoubleKey("color", kNewBackgroundColor); + + fake_plugin_.HandleMessage(message); + EXPECT_EQ(kNewBackgroundColor, fake_plugin_.GetBackgroundColor()); +} + +} // namespace chrome_pdf diff --git a/chromium/pdf/pdf_view_web_plugin.cc b/chromium/pdf/pdf_view_web_plugin.cc index 0891ffbd5ea..c8bc44f814e 100644 --- a/chromium/pdf/pdf_view_web_plugin.cc +++ b/chromium/pdf/pdf_view_web_plugin.cc @@ -12,7 +12,8 @@ #include #include "base/check_op.h" -#include "base/location.h" +#include "base/metrics/user_metrics.h" +#include "base/metrics/user_metrics_action.h" #include "base/notreached.h" #include "base/thread_annotations.h" #include "base/threading/sequenced_task_runner_handle.h" @@ -20,6 +21,9 @@ #include "base/time/time.h" #include "base/values.h" #include "cc/paint/paint_canvas.h" +#include "cc/paint/paint_flags.h" +#include "cc/paint/paint_image.h" +#include "cc/paint/paint_image_builder.h" #include "net/cookies/site_for_cookies.h" #include "pdf/accessibility_structs.h" #include "pdf/pdf_engine.h" @@ -46,7 +50,12 @@ #include "third_party/blink/public/web/web_plugin_container.h" #include "third_party/blink/public/web/web_plugin_params.h" #include "third_party/skia/include/core/SkColor.h" +#include "third_party/skia/include/core/SkRect.h" +#include "third_party/skia/include/core/SkRefCnt.h" #include "ui/base/cursor/cursor.h" +#include "ui/base/cursor/mojom/cursor_type.mojom-shared.h" +#include "ui/gfx/geometry/point.h" +#include "ui/gfx/geometry/rect.h" #include "ui/gfx/skia_util.h" #include "v8/include/v8.h" @@ -115,6 +124,8 @@ bool PdfViewWebPlugin::Initialize(blink::WebPluginContainer* container) { for (size_t i = 0; i < initial_params_.attribute_names.size(); ++i) { if (initial_params_.attribute_names[i] == "stream-url") { stream_url = initial_params_.attribute_values[i].Utf8(); + } else if (initial_params_.attribute_names[i] == "full-frame") { + set_full_frame(true); } else if (initial_params_.attribute_names[i] == "background-color") { SkColor background_color; if (!base::StringToUint(initial_params_.attribute_values[i].Utf8(), @@ -170,12 +181,40 @@ v8::Local PdfViewWebPlugin::V8ScriptableObject( void PdfViewWebPlugin::UpdateAllLifecyclePhases( blink::DocumentUpdateReason reason) {} -void PdfViewWebPlugin::Paint(cc::PaintCanvas* canvas, const gfx::Rect& rect) {} +void PdfViewWebPlugin::Paint(cc::PaintCanvas* canvas, const gfx::Rect& rect) { + const float inverse_scale = 1.0f / device_scale(); + + // Clip the intersection of the paint rect and the plugin rect, so that + // painting outside the plugin or the paint rect area can be avoided. + // Note: `invalidate_rect` and `rect` are in CSS pixels. The plugin rect (with + // the device scale applied) must be converted to CSS pixels as well before + // calculating `invalidate_rect`. + SkRect invalidate_rect = gfx::RectToSkRect(gfx::IntersectRects( + gfx::ScaleToEnclosingRectSafe(plugin_rect(), inverse_scale), rect)); + cc::PaintCanvasAutoRestore auto_restore(canvas, /*save=*/true); + canvas->clipRect(invalidate_rect); + + // Paint with the plugin's background color if the snapshot is not ready. + if (snapshot_.GetSkImageInfo().isEmpty()) { + cc::PaintFlags flags; + flags.setBlendMode(SkBlendMode::kSrc); + flags.setColor(GetBackgroundColor()); + canvas->drawRect(invalidate_rect, flags); + return; + } + + if (inverse_scale != 1.0f) + canvas->scale(inverse_scale, inverse_scale); + + canvas->drawImage(snapshot_, plugin_rect().x(), plugin_rect().y()); +} void PdfViewWebPlugin::UpdateGeometry(const gfx::Rect& window_rect, const gfx::Rect& clip_rect, const gfx::Rect& unobscured_rect, - bool is_visible) {} + bool is_visible) { + OnViewportChanged(window_rect, container_->DeviceScaleFactor()); +} void PdfViewWebPlugin::UpdateFocus(bool focused, blink::mojom::FocusType focus_type) {} @@ -197,27 +236,7 @@ void PdfViewWebPlugin::DidFinishLoading() {} void PdfViewWebPlugin::DidFailLoading(const blink::WebURLError& error) {} -void PdfViewWebPlugin::ProposeDocumentLayout(const DocumentLayout& layout) {} - -void PdfViewWebPlugin::DidScroll(const gfx::Vector2d& offset) {} - -void PdfViewWebPlugin::ScrollToX(int x_in_screen_coords) {} - -void PdfViewWebPlugin::ScrollToY(int y_in_screen_coords) {} - -void PdfViewWebPlugin::ScrollBy(const gfx::Vector2d& scroll_delta) {} - -void PdfViewWebPlugin::ScrollToPage(int page) {} - -void PdfViewWebPlugin::NavigateTo(const std::string& url, - WindowOpenDisposition disposition) {} - -void PdfViewWebPlugin::NavigateToDestination(int page, - const float* x, - const float* y, - const float* zoom) {} - -void PdfViewWebPlugin::UpdateCursor(PP_CursorType_Dev cursor) {} +void PdfViewWebPlugin::UpdateCursor(ui::mojom::CursorType cursor_type) {} void PdfViewWebPlugin::UpdateTickMarks( const std::vector& tickmarks) {} @@ -228,13 +247,6 @@ void PdfViewWebPlugin::NotifyNumberOfFindResultsChanged(int total, void PdfViewWebPlugin::NotifySelectedFindResultChanged(int current_find_index) { } -void PdfViewWebPlugin::NotifyTouchSelectionOccurred() {} - -void PdfViewWebPlugin::GetDocumentPassword( - base::OnceCallback callback) {} - -void PdfViewWebPlugin::Beep() {} - void PdfViewWebPlugin::Alert(const std::string& message) {} bool PdfViewWebPlugin::Confirm(const std::string& message) { @@ -246,41 +258,19 @@ std::string PdfViewWebPlugin::Prompt(const std::string& question, return ""; } -std::string PdfViewWebPlugin::GetURL() { - return ""; -} - -void PdfViewWebPlugin::Email(const std::string& to, - const std::string& cc, - const std::string& bcc, - const std::string& subject, - const std::string& body) {} - void PdfViewWebPlugin::Print() {} void PdfViewWebPlugin::SubmitForm(const std::string& url, const void* data, int length) {} -std::unique_ptr PdfViewWebPlugin::CreateUrlLoader() { - return nullptr; -} - std::vector -PdfViewWebPlugin::SearchString(const base::char16* string, - const base::char16* term, +PdfViewWebPlugin::SearchString(const char16_t* string, + const char16_t* term, bool case_sensitive) { return {}; } -void PdfViewWebPlugin::DocumentLoadComplete() { - NOTIMPLEMENTED(); -} - -void PdfViewWebPlugin::DocumentLoadFailed() { - NOTIMPLEMENTED(); -} - pp::Instance* PdfViewWebPlugin::GetPluginInstance() { return nullptr; } @@ -288,24 +278,15 @@ pp::Instance* PdfViewWebPlugin::GetPluginInstance() { void PdfViewWebPlugin::DocumentHasUnsupportedFeature( const std::string& feature) {} -void PdfViewWebPlugin::DocumentLoadProgress(uint32_t available, - uint32_t doc_size) {} - -void PdfViewWebPlugin::FormTextFieldFocusChange(bool in_focus) {} - bool PdfViewWebPlugin::IsPrintPreview() { return false; } -void PdfViewWebPlugin::IsSelectingChanged(bool is_selecting) {} - void PdfViewWebPlugin::SelectionChanged(const gfx::Rect& left, const gfx::Rect& right) {} void PdfViewWebPlugin::EnteredEditMode() {} -void PdfViewWebPlugin::DocumentFocusChanged(bool document_has_focus) {} - void PdfViewWebPlugin::SetSelectedText(const std::string& selected_text) { NOTIMPLEMENTED(); } @@ -321,21 +302,23 @@ bool PdfViewWebPlugin::IsValidLink(const std::string& url) { std::unique_ptr PdfViewWebPlugin::CreatePaintGraphics( const gfx::Size& size) { - auto graphics = SkiaGraphics::Create(size); + // `this` must be valid when creating new graphics. `this` is guaranteed to + // outlive `graphics`; the implemented client interface owns the paint manager + // in which the graphics device exists. + auto graphics = SkiaGraphics::Create(this, size); DCHECK(graphics); return graphics; } bool PdfViewWebPlugin::BindPaintGraphics(Graphics& graphics) { - NOTIMPLEMENTED_LOG_ONCE(); + InvalidatePluginContainer(); return false; } -void PdfViewWebPlugin::ScheduleTaskOnMainThread( - base::TimeDelta delay, - ResultCallback callback, - int32_t result, - const base::Location& from_here) { +void PdfViewWebPlugin::ScheduleTaskOnMainThread(const base::Location& from_here, + ResultCallback callback, + int32_t result, + base::TimeDelta delay) { base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( from_here, base::BindOnce(std::move(callback), result), delay); } @@ -375,6 +358,15 @@ void PdfViewWebPlugin::OnMessage(const base::Value& message) { PdfViewPluginBase::HandleMessage(message); } +void PdfViewWebPlugin::UpdateSnapshot(sk_sp snapshot) { + snapshot_ = + cc::PaintImageBuilder::WithDefault() + .set_image(std::move(snapshot), cc::PaintImage::GetNextContentId()) + .set_id(cc::PaintImage::GetNextId()) + .TakePaintImage(); + InvalidateRectInPluginContainer(gfx::Rect(plugin_rect().size())); +} + base::WeakPtr PdfViewWebPlugin::GetWeakPtr() { return weak_factory_.GetWeakPtr(); } @@ -409,6 +401,10 @@ void PdfViewWebPlugin::InitImageData(const gfx::Size& size) { mutable_image_data() = CreateN32PremulSkBitmap(gfx::SizeToSkISize(size)); } +void PdfViewWebPlugin::SetFormFieldInFocus(bool in_focus) { + NOTIMPLEMENTED(); +} + // TODO(https://crbug.com/1144444): Add a Pepper-free implementation to set // accessibility document information. void PdfViewWebPlugin::SetAccessibilityDocInfo( @@ -433,7 +429,27 @@ void PdfViewWebPlugin::SetAccessibilityViewportInfo( NOTIMPLEMENTED(); } -void PdfViewWebPlugin::OnViewportChanged(gfx::Rect view_rect, +void PdfViewWebPlugin::SetContentRestrictions(int content_restrictions) { + NOTIMPLEMENTED(); +} + +void PdfViewWebPlugin::DidStartLoading() { + NOTIMPLEMENTED(); +} + +void PdfViewWebPlugin::DidStopLoading() { + NOTIMPLEMENTED(); +} + +void PdfViewWebPlugin::OnPrintPreviewLoaded() { + NOTIMPLEMENTED(); +} + +void PdfViewWebPlugin::UserMetricsRecordAction(const std::string& action) { + base::RecordAction(base::UserMetricsAction(action.c_str())); +} + +void PdfViewWebPlugin::OnViewportChanged(const gfx::Rect& view_rect, float new_device_scale) { UpdateGeometryOnViewChanged(view_rect, new_device_scale); @@ -441,4 +457,19 @@ void PdfViewWebPlugin::OnViewportChanged(gfx::Rect view_rect, // print preview plugin. } +void PdfViewWebPlugin::InvalidatePluginContainer() { + DCHECK(container_); + + container_->Invalidate(); +} + +void PdfViewWebPlugin::InvalidateRectInPluginContainer(const gfx::Rect& rect) { + DCHECK(container_); + + if (plugin_rect().IsEmpty()) + return; + + container_->InvalidateRect(rect); +} + } // namespace chrome_pdf diff --git a/chromium/pdf/pdf_view_web_plugin.h b/chromium/pdf/pdf_view_web_plugin.h index 0f23d532490..72a94d14098 100644 --- a/chromium/pdf/pdf_view_web_plugin.h +++ b/chromium/pdf/pdf_view_web_plugin.h @@ -5,20 +5,17 @@ #ifndef PDF_PDF_VIEW_WEB_PLUGIN_H_ #define PDF_PDF_VIEW_WEB_PLUGIN_H_ -#include "base/location.h" #include "base/memory/weak_ptr.h" +#include "cc/paint/paint_image.h" #include "pdf/pdf_view_plugin_base.h" #include "pdf/post_message_receiver.h" #include "pdf/post_message_sender.h" +#include "pdf/ppapi_migration/graphics.h" #include "pdf/ppapi_migration/url_loader.h" #include "third_party/blink/public/web/web_plugin.h" #include "third_party/blink/public/web/web_plugin_params.h" #include "v8/include/v8.h" -namespace base { -class Value; -} // namespace base - namespace blink { class WebPluginContainer; } // namespace blink @@ -29,7 +26,8 @@ namespace chrome_pdf { class PdfViewWebPlugin final : public PdfViewPluginBase, public blink::WebPlugin, public BlinkUrlLoader::Client, - public PostMessageReceiver::Client { + public PostMessageReceiver::Client, + public SkiaGraphics::Client { public: explicit PdfViewWebPlugin(const blink::WebPluginParams& params); PdfViewWebPlugin(const PdfViewWebPlugin& other) = delete; @@ -57,65 +55,35 @@ class PdfViewWebPlugin final : public PdfViewPluginBase, void DidFailLoading(const blink::WebURLError& error) override; // PdfViewPluginBase: - void ProposeDocumentLayout(const DocumentLayout& layout) override; - void DidScroll(const gfx::Vector2d& offset) override; - void ScrollToX(int x_in_screen_coords) override; - void ScrollToY(int y_in_screen_coords) override; - void ScrollBy(const gfx::Vector2d& scroll_delta) override; - void ScrollToPage(int page) override; - void NavigateTo(const std::string& url, - WindowOpenDisposition disposition) override; - void NavigateToDestination(int page, - const float* x, - const float* y, - const float* zoom) override; - void UpdateCursor(PP_CursorType_Dev cursor) override; + void UpdateCursor(ui::mojom::CursorType cursor_type) override; void UpdateTickMarks(const std::vector& tickmarks) override; void NotifyNumberOfFindResultsChanged(int total, bool final_result) override; void NotifySelectedFindResultChanged(int current_find_index) override; - void NotifyTouchSelectionOccurred() override; - void GetDocumentPassword( - base::OnceCallback callback) override; - void Beep() override; void Alert(const std::string& message) override; bool Confirm(const std::string& message) override; std::string Prompt(const std::string& question, const std::string& default_answer) override; - std::string GetURL() override; - void Email(const std::string& to, - const std::string& cc, - const std::string& bcc, - const std::string& subject, - const std::string& body) override; void Print() override; void SubmitForm(const std::string& url, const void* data, int length) override; - std::unique_ptr CreateUrlLoader() override; - std::vector SearchString(const base::char16* string, - const base::char16* term, + std::vector SearchString(const char16_t* string, + const char16_t* term, bool case_sensitive) override; - void DocumentLoadComplete() override; - void DocumentLoadFailed() override; pp::Instance* GetPluginInstance() override; void DocumentHasUnsupportedFeature(const std::string& feature) override; - void DocumentLoadProgress(uint32_t available, uint32_t doc_size) override; - void FormTextFieldFocusChange(bool in_focus) override; bool IsPrintPreview() override; - void IsSelectingChanged(bool is_selecting) override; void SelectionChanged(const gfx::Rect& left, const gfx::Rect& right) override; void EnteredEditMode() override; - void DocumentFocusChanged(bool document_has_focus) override; void SetSelectedText(const std::string& selected_text) override; void SetLinkUnderCursor(const std::string& link_under_cursor) override; bool IsValidLink(const std::string& url) override; std::unique_ptr CreatePaintGraphics(const gfx::Size& size) override; bool BindPaintGraphics(Graphics& graphics) override; - void ScheduleTaskOnMainThread( - base::TimeDelta delay, - ResultCallback callback, - int32_t result, - const base::Location& from_here = base::Location::Current()) override; + void ScheduleTaskOnMainThread(const base::Location& from_here, + ResultCallback callback, + int32_t result, + base::TimeDelta delay) override; // BlinkUrlLoader::Client: bool IsValid() const override; @@ -129,6 +97,9 @@ class PdfViewWebPlugin final : public PdfViewPluginBase, // PostMessageReceiver::Client: void OnMessage(const base::Value& message) override; + // SkiaGraphics::Client: + void UpdateSnapshot(sk_sp snapshot) override; + protected: // PdfViewPluginBase: base::WeakPtr GetWeakPtr() override; @@ -138,6 +109,7 @@ class PdfViewWebPlugin final : public PdfViewPluginBase, int32_t result) override; void SendMessage(base::Value message) override; void InitImageData(const gfx::Size& size) override; + void SetFormFieldInFocus(bool in_focus) override; void SetAccessibilityDocInfo(const AccessibilityDocInfo& doc_info) override; void SetAccessibilityPageInfo(AccessibilityPageInfo page_info, std::vector text_runs, @@ -145,12 +117,25 @@ class PdfViewWebPlugin final : public PdfViewPluginBase, AccessibilityPageObjects page_objects) override; void SetAccessibilityViewportInfo( const AccessibilityViewportInfo& viewport_info) override; + void SetContentRestrictions(int content_restrictions) override; + void DidStartLoading() override; + void DidStopLoading() override; + void OnPrintPreviewLoaded() override; + void UserMetricsRecordAction(const std::string& action) override; private: // Call `Destroy()` instead. ~PdfViewWebPlugin() override; - void OnViewportChanged(gfx::Rect view_rect, float new_device_scale); + void OnViewportChanged(const gfx::Rect& view_rect, float new_device_scale); + + // Invalidates the entire web plugin container and schedules a paint of the + // page in it. + void InvalidatePluginContainer(); + + // Schedules a paint of the page of a given region in the web plugin + // container. The coordinates are relative to the top-left of the container. + void InvalidateRectInPluginContainer(const gfx::Rect& rect); blink::WebPluginParams initial_params_; blink::WebPluginContainer* container_ = nullptr; @@ -158,6 +143,8 @@ class PdfViewWebPlugin final : public PdfViewPluginBase, v8::Persistent scriptable_receiver_; PostMessageSender post_message_sender_; + cc::PaintImage snapshot_; + base::WeakPtrFactory weak_factory_{this}; }; diff --git a/chromium/pdf/pdfium/DEPS b/chromium/pdf/pdfium/DEPS index 446fbe1bfa7..16ff3841b22 100644 --- a/chromium/pdf/pdfium/DEPS +++ b/chromium/pdf/pdfium/DEPS @@ -1,10 +1,5 @@ include_rules = [ - "+gin/array_buffer.h", - "+gin/v8_initializer.h", - "+printing/nup_parameters.h", - "+printing/page_setup.h", - "+printing/pdf_render_settings.h", "+third_party/pdfium/public", - "+ui/gfx/codec/jpeg_codec.h", + "+ui/gfx/codec", "+v8/include/cppgc/platform.h", ] diff --git a/chromium/pdf/pdfium/findtext_unittest.cc b/chromium/pdf/pdfium/findtext_unittest.cc index 818a6f606d4..acca90d79c8 100644 --- a/chromium/pdf/pdfium/findtext_unittest.cc +++ b/chromium/pdf/pdfium/findtext_unittest.cc @@ -27,19 +27,19 @@ class FindTextTestClient : public TestClient { MOCK_METHOD(void, NotifyNumberOfFindResultsChanged, (int, bool), (override)); MOCK_METHOD(void, NotifySelectedFindResultChanged, (int), (override)); - std::vector SearchString(const base::char16* string, - const base::char16* term, + std::vector SearchString(const char16_t* string, + const char16_t* term, bool case_sensitive) override { EXPECT_TRUE(case_sensitive); - base::string16 haystack = base::string16(string); - base::string16 needle = base::string16(term); + std::u16string haystack = std::u16string(string); + std::u16string needle = std::u16string(term); std::vector results; size_t pos = 0; while (1) { pos = haystack.find(needle, pos); - if (pos == base::string16::npos) + if (pos == std::u16string::npos) break; SearchStringResult result; @@ -145,7 +145,7 @@ TEST_F(FindTextTest, FindFancyQuotationMarkText) { } // don't, using right apostrophe instead of a single quotation mark - base::string16 term = {'d', 'o', 'n', 0x2019, 't'}; + std::u16string term = {'d', 'o', 'n', 0x2019, 't'}; engine->StartFind(base::UTF16ToUTF8(term), /*case_sensitive=*/true); } diff --git a/chromium/pdf/pdfium/pdfium_api_string_buffer_adapter.cc b/chromium/pdf/pdfium/pdfium_api_string_buffer_adapter.cc index 9e02e34906f..35da69a615e 100644 --- a/chromium/pdf/pdfium/pdfium_api_string_buffer_adapter.cc +++ b/chromium/pdf/pdfium/pdfium_api_string_buffer_adapter.cc @@ -52,11 +52,11 @@ void PDFiumAPIStringBufferAdapter::Close(size_t actual_size) { } PDFiumAPIStringBufferSizeInBytesAdapter:: - PDFiumAPIStringBufferSizeInBytesAdapter(base::string16* str, + PDFiumAPIStringBufferSizeInBytesAdapter(std::u16string* str, size_t expected_size, bool check_expected_size) - : adapter_(str, expected_size / sizeof(base::char16), check_expected_size) { - DCHECK(expected_size % sizeof(base::char16) == 0); + : adapter_(str, expected_size / sizeof(char16_t), check_expected_size) { + DCHECK(expected_size % sizeof(char16_t) == 0); } PDFiumAPIStringBufferSizeInBytesAdapter:: @@ -67,13 +67,13 @@ void* PDFiumAPIStringBufferSizeInBytesAdapter::GetData() { } void PDFiumAPIStringBufferSizeInBytesAdapter::Close(size_t actual_size) { - DCHECK(actual_size % sizeof(base::char16) == 0); - adapter_.Close(actual_size / sizeof(base::char16)); + DCHECK(actual_size % sizeof(char16_t) == 0); + adapter_.Close(actual_size / sizeof(char16_t)); } // explicit instantiations template class PDFiumAPIStringBufferAdapter; -template class PDFiumAPIStringBufferAdapter; +template class PDFiumAPIStringBufferAdapter; } // namespace internal diff --git a/chromium/pdf/pdfium/pdfium_api_string_buffer_adapter.h b/chromium/pdf/pdfium/pdfium_api_string_buffer_adapter.h index 320488b855a..4eaaf3c7663 100644 --- a/chromium/pdf/pdfium/pdfium_api_string_buffer_adapter.h +++ b/chromium/pdf/pdfium/pdfium_api_string_buffer_adapter.h @@ -12,7 +12,6 @@ #include "base/callback.h" #include "base/numerics/safe_math.h" #include "base/optional.h" -#include "base/strings/string16.h" namespace chrome_pdf { @@ -20,7 +19,7 @@ namespace internal { // Helper to deal with the fact that many PDFium APIs write the null-terminator // into string buffers that are passed to them, but the PDF code likes to use -// std::strings / base::string16s, where one should not count on the internal +// std::strings / std::u16strings, where one should not count on the internal // string buffers to be null-terminated. template class PDFiumAPIStringBufferAdapter { @@ -63,7 +62,7 @@ class PDFiumAPIStringBufferAdapter { // Helper to deal with the fact that many PDFium APIs write the null-terminator // into string buffers that are passed to them, but the PDF code likes to use -// std::strings / base::string16s, where one should not count on the internal +// std::strings / std::u16strings, where one should not count on the internal // string buffers to be null-terminated. This version is suitable for APIs that // work in terms of number of bytes instead of the number of characters. Though // for std::strings, PDFiumAPIStringBufferAdapter is equivalent. @@ -75,17 +74,17 @@ class PDFiumAPIStringBufferSizeInBytesAdapter { // character in bytes. // |check_expected_size| whether to check the actual number of bytes // written into |str| against |expected_size| when calling Close(). - PDFiumAPIStringBufferSizeInBytesAdapter(base::string16* str, + PDFiumAPIStringBufferSizeInBytesAdapter(std::u16string* str, size_t expected_size, bool check_expected_size); ~PDFiumAPIStringBufferSizeInBytesAdapter(); // Returns a pointer to |str_|'s buffer. The buffer's size is large enough to - // hold |expected_size_| + sizeof(base::char16) bytes, so the PDFium API that + // hold |expected_size_| + sizeof(char16_t) bytes, so the PDFium API that // uses the pointer has space to write a null-terminator. void* GetData(); - // Resizes |str_| to |actual_size| - sizeof(base::char16) bytes, thereby + // Resizes |str_| to |actual_size| - sizeof(char16_t) bytes, thereby // removing the extra null-terminator. This must be called prior to the // adapter's destruction. The pointer returned by GetData() should be // considered invalid. @@ -97,7 +96,7 @@ class PDFiumAPIStringBufferSizeInBytesAdapter { } private: - PDFiumAPIStringBufferAdapter adapter_; + PDFiumAPIStringBufferAdapter adapter_; }; template -base::string16 CallPDFiumWideStringBufferApi( +std::u16string CallPDFiumWideStringBufferApi( base::RepeatingCallback api, bool check_expected_size) { using adapter_type = internal::PDFiumAPIStringBufferSizeInBytesAdapter; - return internal::CallPDFiumStringBufferApi( + return internal::CallPDFiumStringBufferApi( api, check_expected_size); } // Variant of CallPDFiumWideStringBufferApi() that distinguishes between API // call failures and empty string return values. template -base::Optional CallPDFiumWideStringBufferApiAndReturnOptional( +base::Optional CallPDFiumWideStringBufferApiAndReturnOptional( base::RepeatingCallback api, bool check_expected_size) { using adapter_type = internal::PDFiumAPIStringBufferSizeInBytesAdapter; return internal::CallPDFiumStringBufferApiAndReturnOptional( + std::u16string>( api, check_expected_size); } diff --git a/chromium/pdf/pdfium/pdfium_assert_matching_enums.cc b/chromium/pdf/pdfium/pdfium_assert_matching_enums.cc index 0943ce91409..49faf44e9cb 100644 --- a/chromium/pdf/pdfium/pdfium_assert_matching_enums.cc +++ b/chromium/pdf/pdfium/pdfium_assert_matching_enums.cc @@ -4,6 +4,7 @@ #include "build/build_config.h" #include "pdf/accessibility_structs.h" +#include "pdf/content_restriction.h" #include "pdf/document_metadata.h" #include "pdf/ppapi_migration/input_event_conversions.h" #include "ppapi/c/pp_input_event.h" @@ -394,3 +395,14 @@ STATIC_ASSERT_ENUM(chrome_pdf::AccessibilityScrollAlignment::kClosestToEdge, PP_PDF_SCROLL_ALIGNMENT_CLOSEST_EDGE); STATIC_ASSERT_ENUM(chrome_pdf::AccessibilityScrollAlignment::kMaxValue, PP_PDF_ACCESSIBILITYSCROLLALIGNMENT_LAST); + +STATIC_ASSERT_ENUM(chrome_pdf::kContentRestrictionCopy, + PP_CONTENT_RESTRICTION_COPY); +STATIC_ASSERT_ENUM(chrome_pdf::kContentRestrictionCut, + PP_CONTENT_RESTRICTION_CUT); +STATIC_ASSERT_ENUM(chrome_pdf::kContentRestrictionPaste, + PP_CONTENT_RESTRICTION_PASTE); +STATIC_ASSERT_ENUM(chrome_pdf::kContentRestrictionPrint, + PP_CONTENT_RESTRICTION_PRINT); +STATIC_ASSERT_ENUM(chrome_pdf::kContentRestrictionSave, + PP_CONTENT_RESTRICTION_SAVE); diff --git a/chromium/pdf/pdfium/pdfium_engine.cc b/chromium/pdf/pdfium/pdfium_engine.cc index 5490772654c..64b4133ff95 100644 --- a/chromium/pdf/pdfium/pdfium_engine.cc +++ b/chromium/pdf/pdfium/pdfium_engine.cc @@ -20,6 +20,7 @@ #include "base/check_op.h" #include "base/debug/alias.h" #include "base/feature_list.h" +#include "base/location.h" #include "base/notreached.h" #include "base/stl_util.h" #include "base/strings/string_util.h" @@ -62,6 +63,7 @@ #include "third_party/pdfium/public/fpdf_ppo.h" #include "third_party/pdfium/public/fpdf_searchex.h" #include "third_party/skia/include/core/SkBitmap.h" +#include "ui/base/cursor/mojom/cursor_type.mojom-shared.h" #include "ui/events/keycodes/keyboard_codes.h" #include "ui/gfx/geometry/point.h" #include "ui/gfx/geometry/point_conversions.h" @@ -145,7 +147,7 @@ int CalculateCenterForZoom(int center, int length, double zoom) { // as Adobe Reader. When a hyphen is encountered, the next non-CR/LF whitespace // becomes CR+LF and the hyphen is erased. If there is no whitespace between // two hyphens, the latter hyphen is erased and ignored. -void FormatStringWithHyphens(base::string16* text) { +void FormatStringWithHyphens(std::u16string* text) { // First pass marks all the hyphen positions. struct HyphenPosition { HyphenPosition() : position(0), next_whitespace_position(0) {} @@ -155,10 +157,10 @@ void FormatStringWithHyphens(base::string16* text) { std::vector hyphen_positions; HyphenPosition current_hyphen_position; bool current_hyphen_position_is_valid = false; - constexpr base::char16 kPdfiumHyphenEOL = 0xfffe; + constexpr char16_t kPdfiumHyphenEOL = 0xfffe; for (size_t i = 0; i < text->size(); ++i) { - const base::char16& current_char = (*text)[i]; + const char16_t& current_char = (*text)[i]; if (current_char == kPdfiumHyphenEOL) { if (current_hyphen_position_is_valid) hyphen_positions.push_back(current_hyphen_position); @@ -179,7 +181,7 @@ void FormatStringWithHyphens(base::string16* text) { // With all the hyphen positions, do the search and replace. while (!hyphen_positions.empty()) { - static constexpr base::char16 kCr[] = {L'\r', L'\0'}; + static constexpr char16_t kCr[] = {L'\r', L'\0'}; const HyphenPosition& position = hyphen_positions.back(); if (position.next_whitespace_position != 0) { (*text)[position.next_whitespace_position] = L'\n'; @@ -190,16 +192,16 @@ void FormatStringWithHyphens(base::string16* text) { } // Adobe Reader also get rid of trailing spaces right before a CRLF. - static constexpr base::char16 kSpaceCrCn[] = {L' ', L'\r', L'\n', L'\0'}; - static constexpr base::char16 kCrCn[] = {L'\r', L'\n', L'\0'}; + static constexpr char16_t kSpaceCrCn[] = {L' ', L'\r', L'\n', L'\0'}; + static constexpr char16_t 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) { +void FormatStringForOS(std::u16string* text) { #if defined(OS_POSIX) - static constexpr base::char16 kCr[] = {L'\r', L'\0'}; - static constexpr base::char16 kBlank[] = {L'\0'}; + static constexpr char16_t kCr[] = {L'\r', L'\0'}; + static constexpr char16_t kBlank[] = {L'\0'}; base::ReplaceChars(*text, kCr, kBlank, text); #elif defined(OS_WIN) // Do nothing @@ -213,7 +215,7 @@ void FormatStringForOS(base::string16* text) { // For triple clicks, look for line breaks. // The actual algorithm used in Blink is much more complicated, so do a simple // approximation. -bool FindMultipleClickBoundary(bool is_double_click, base::char16 cur) { +bool FindMultipleClickBoundary(bool is_double_click, char16_t cur) { if (!is_double_click) return cur == '\n'; @@ -377,20 +379,21 @@ PP_PrivateFocusObjectType GetAnnotationFocusType( } } -base::string16 GetAttachmentAttribute(FPDF_ATTACHMENT attachment, +std::u16string GetAttachmentAttribute(FPDF_ATTACHMENT attachment, FPDF_BYTESTRING field) { return CallPDFiumWideStringBufferApi( base::BindRepeating(&FPDFAttachment_GetStringValue, attachment, field), /*check_expected_size=*/true); } -base::string16 GetAttachmentName(FPDF_ATTACHMENT attachment) { +std::u16string GetAttachmentName(FPDF_ATTACHMENT attachment) { return CallPDFiumWideStringBufferApi( base::BindRepeating(&FPDFAttachment_GetName, attachment), /*check_expected_size=*/true); } std::string GetXYZParamsString(FPDF_DEST dest, PDFiumPage* page) { + std::string xyz_params; FPDF_BOOL has_x_coord; FPDF_BOOL has_y_coord; FPDF_BOOL has_zoom; @@ -399,28 +402,26 @@ std::string GetXYZParamsString(FPDF_DEST dest, PDFiumPage* page) { FS_FLOAT zoom; if (!FPDFDest_GetLocationInPage(dest, &has_x_coord, &has_y_coord, &has_zoom, &x, &y, &zoom)) { - return ""; + return xyz_params; } - // Handle out-of-range page coordinates. - x = has_x_coord ? page->PreProcessInPageCoordX(x) : 0; - y = has_y_coord ? page->PreProcessInPageCoordY(y) : 0; - - // Convert in-page coordinates to in-screen coordinates. - gfx::PointF xy(x, y); - gfx::PointF screen_coords = page->TransformPageToScreenXY(xy); - // Generate a string of the parameters - std::string xyz_params; - if (has_x_coord) - xyz_params = base::NumberToString(screen_coords.x()) + ","; - else + if (has_x_coord) { + // Handle out-of-range page coordinates and convert in-page coordinates to + // in-screen coordinates. + xyz_params = + base::NumberToString(page->PreProcessAndTransformInPageCoordX(x)) + ","; + } else { xyz_params = "null,"; + } - if (has_y_coord) - xyz_params += base::NumberToString(screen_coords.y()) + ","; - else + if (has_y_coord) { + // Same conversions as x coordinates above. + xyz_params += + base::NumberToString(page->PreProcessAndTransformInPageCoordY(y)) + ","; + } else { xyz_params += "null,"; + } if (has_zoom) { if (zoom == 0.0f) @@ -1130,7 +1131,7 @@ bool PDFiumEngine::ReadLoadedBytes(uint32_t length, void* buffer) { void PDFiumEngine::SetFormSelectedText(FPDF_FORMHANDLE form_handle, FPDF_PAGE page) { - base::string16 selected_form_text16 = CallPDFiumWideStringBufferApi( + std::u16string selected_form_text16 = CallPDFiumWideStringBufferApi( base::BindRepeating(&FORM_GetSelectedText, form_handle, page), /*check_expected_size=*/false); @@ -1213,7 +1214,7 @@ void PDFiumEngine::OnMultipleClick(int click_count, // now it doesn't. int start_index = char_index; do { - base::char16 cur = pages_[page_index]->GetCharAtIndex(start_index); + char16_t cur = pages_[page_index]->GetCharAtIndex(start_index); if (FindMultipleClickBoundary(is_double_click, cur)) break; } while (--start_index >= 0); @@ -1223,7 +1224,7 @@ void PDFiumEngine::OnMultipleClick(int click_count, int end_index = char_index; int total = pages_[page_index]->GetCharCount(); while (end_index++ <= total) { - base::char16 cur = pages_[page_index]->GetCharAtIndex(end_index); + char16_t cur = pages_[page_index]->GetCharAtIndex(end_index); if (FindMultipleClickBoundary(is_double_click, cur)) break; } @@ -1324,7 +1325,7 @@ bool PDFiumEngine::OnMiddleMouseDown(const MouseInputEvent& event) { if (kViewerImplementedPanning) { // Switch to hand cursor when panning. - client_->UpdateCursor(PP_CURSORTYPE_HAND); + client_->UpdateCursor(ui::mojom::CursorType::kHand); } // Prevent middle mouse button from selecting texts. @@ -1544,18 +1545,17 @@ bool PDFiumEngine::OnMouseMove(const MouseInputEvent& event) { return ExtendSelection(page_index, char_index); } -PP_CursorType_Dev PDFiumEngine::DetermineCursorType(PDFiumPage::Area area, - int form_type) const { - if (kViewerImplementedPanning && mouse_middle_button_down_) { - return PP_CURSORTYPE_HAND; - } +ui::mojom::CursorType PDFiumEngine::DetermineCursorType(PDFiumPage::Area area, + int form_type) const { + if (kViewerImplementedPanning && mouse_middle_button_down_) + return ui::mojom::CursorType::kHand; switch (area) { case PDFiumPage::TEXT_AREA: - return PP_CURSORTYPE_IBEAM; + return ui::mojom::CursorType::kIBeam; case PDFiumPage::WEBLINK_AREA: case PDFiumPage::DOCLINK_AREA: - return PP_CURSORTYPE_HAND; + return ui::mojom::CursorType::kHand; case PDFiumPage::NONSELECTABLE_AREA: case PDFiumPage::FORM_TEXT_AREA: default: @@ -1565,9 +1565,9 @@ PP_CursorType_Dev PDFiumEngine::DetermineCursorType(PDFiumPage::Area area, case FPDF_FORMFIELD_RADIOBUTTON: case FPDF_FORMFIELD_COMBOBOX: case FPDF_FORMFIELD_LISTBOX: - return PP_CURSORTYPE_HAND; + return ui::mojom::CursorType::kHand; case FPDF_FORMFIELD_TEXTFIELD: - return PP_CURSORTYPE_IBEAM; + return ui::mojom::CursorType::kIBeam; #if defined(PDF_ENABLE_XFA) case FPDF_FORMFIELD_XFA_CHECKBOX: case FPDF_FORMFIELD_XFA_COMBOBOX: @@ -1575,12 +1575,12 @@ PP_CursorType_Dev PDFiumEngine::DetermineCursorType(PDFiumPage::Area area, case FPDF_FORMFIELD_XFA_LISTBOX: case FPDF_FORMFIELD_XFA_PUSHBUTTON: case FPDF_FORMFIELD_XFA_SIGNATURE: - return PP_CURSORTYPE_HAND; + return ui::mojom::CursorType::kHand; case FPDF_FORMFIELD_XFA_TEXTFIELD: - return PP_CURSORTYPE_IBEAM; + return ui::mojom::CursorType::kIBeam; #endif default: - return PP_CURSORTYPE_POINTER; + return ui::mojom::CursorType::kPointer; } } } @@ -1718,7 +1718,7 @@ bool PDFiumEngine::OnChar(const KeyboardInputEvent& event) { if (last_focused_page_ == -1) return false; - base::string16 str = base::UTF8ToUTF16(event.GetKeyChar()); + std::u16string str = base::UTF8ToUTF16(event.GetKeyChar()); bool rv = !!FORM_OnChar(form(), pages_[last_focused_page_]->GetPage(), str[0], event.GetModifiers()); @@ -1770,7 +1770,7 @@ void PDFiumEngine::StartFind(const std::string& text, bool case_sensitive) { int current_page = next_page_to_search_; if (pages_[current_page]->available()) { - base::string16 str = base::UTF8ToUTF16(text); + std::u16string str = base::UTF8ToUTF16(text); // Don't use PDFium to search for now, since it doesn't support unicode // text. Leave the code for now to avoid bit-rot, in case it's fixed later. // The extra parens suppress a -Wunreachable-code warning. @@ -1818,14 +1818,14 @@ void PDFiumEngine::StartFind(const std::string& text, bool case_sensitive) { ContinueFind(case_sensitive ? 1 : 0); } else { client_->ScheduleTaskOnMainThread( - base::TimeDelta(), + FROM_HERE, base::BindOnce(&PDFiumEngine::ContinueFind, find_weak_factory_.GetWeakPtr()), - case_sensitive ? 1 : 0); + case_sensitive ? 1 : 0, base::TimeDelta()); } } -void PDFiumEngine::SearchUsingPDFium(const base::string16& term, +void PDFiumEngine::SearchUsingPDFium(const std::u16string& term, bool case_sensitive, bool first_search, int character_to_start_searching_from, @@ -1857,7 +1857,7 @@ void PDFiumEngine::SearchUsingPDFium(const base::string16& term, FPDFText_FindClose(find); } -void PDFiumEngine::SearchUsingICU(const base::string16& term, +void PDFiumEngine::SearchUsingICU(const std::u16string& term, bool case_sensitive, bool first_search, int character_to_start_searching_from, @@ -1866,8 +1866,8 @@ void PDFiumEngine::SearchUsingICU(const base::string16& term, // Various types of quotions marks need to be converted to the simple ASCII // version for searching to get better matching. - base::string16 adjusted_term = term; - for (base::char16& c : adjusted_term) + std::u16string adjusted_term = term; + for (char16_t& c : adjusted_term) c = SimplifyForSearch(c); const int original_text_length = pages_[current_page]->GetCharCount(); @@ -1881,8 +1881,8 @@ void PDFiumEngine::SearchUsingICU(const base::string16& term, if (text_length <= 0) return; - base::string16 page_text; - PDFiumAPIStringBufferAdapter api_string_adapter( + std::u16string page_text; + PDFiumAPIStringBufferAdapter api_string_adapter( &page_text, text_length, false); unsigned short* data = reinterpret_cast(api_string_adapter.GetData()); @@ -1891,7 +1891,7 @@ 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; + std::u16string 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 @@ -1905,7 +1905,7 @@ void PDFiumEngine::SearchUsingICU(const base::string16& term, // 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]; + char16_t c = page_text[i]; // Collapse whitespace regions by inserting a ' ' into the // adjusted text and recording any removed whitespace indices as preceding // it. @@ -2177,10 +2177,10 @@ std::string PDFiumEngine::GetSelectedText() { if (!HasPermission(PDFEngine::PERMISSION_COPY)) return std::string(); - base::string16 result; + std::u16string result; for (size_t i = 0; i < selection_.size(); ++i) { - static constexpr base::char16 kNewLineChar = L'\n'; - base::string16 current_selection_text = selection_[i].GetText(); + static constexpr char16_t kNewLineChar = L'\n'; + std::u16string current_selection_text = selection_[i].GetText(); if (i != 0) { if (selection_[i - 1].page_index() > selection_[i].page_index()) std::swap(current_selection_text, result); @@ -2210,7 +2210,7 @@ bool PDFiumEngine::HasEditableText() { void PDFiumEngine::ReplaceSelection(const std::string& text) { DCHECK(CanEditText()); if (last_focused_page_ != -1) { - base::string16 text_wide = base::UTF8ToUTF16(text); + std::u16string text_wide = base::UTF8ToUTF16(text); FPDF_WIDESTRING text_pdf_wide = reinterpret_cast(text_wide.c_str()); @@ -2364,7 +2364,7 @@ base::Value PDFiumEngine::GetBookmarks() { base::Value PDFiumEngine::TraverseBookmarks(FPDF_BOOKMARK bookmark, unsigned int depth) { base::Value dict(base::Value::Type::DICTIONARY); - base::string16 title = CallPDFiumWideStringBufferApi( + std::u16string title = CallPDFiumWideStringBufferApi( base::BindRepeating(&FPDFBookmark_GetTitle, bookmark), /*check_expected_size=*/true); dict.SetStringKey("title", title); @@ -2487,7 +2487,7 @@ base::Optional PDFiumEngine::GetNamedDestination( FPDF_DEST dest = FPDF_GetNamedDestByName(doc(), destination.c_str()); if (!dest) { // Look for a bookmark with the same name. - base::string16 destination_wide = base::UTF8ToUTF16(destination); + std::u16string destination_wide = base::UTF8ToUTF16(destination); FPDF_WIDESTRING destination_pdf_wide = reinterpret_cast(destination_wide.c_str()); FPDF_BOOKMARK bookmark = FPDFBookmark_Find(doc(), destination_pdf_wide); @@ -3761,7 +3761,7 @@ void PDFiumEngine::SetSelecting(bool selecting) { bool was_selecting = selecting_; selecting_ = selecting; if (selecting_ != was_selecting) - client_->IsSelectingChanged(selecting); + client_->SetIsSelecting(selecting); } void PDFiumEngine::EnteredEditMode() { @@ -4055,7 +4055,7 @@ std::string PDFiumEngine::GetTrimmedMetadataByField( FPDF_BYTESTRING field) const { DCHECK(doc()); - base::string16 metadata = CallPDFiumWideStringBufferApi( + std::u16string metadata = CallPDFiumWideStringBufferApi( base::BindRepeating(&FPDF_GetMetaText, doc(), field), /*check_expected_size=*/false); diff --git a/chromium/pdf/pdfium/pdfium_engine.h b/chromium/pdf/pdfium/pdfium_engine.h index 3f3cf14ce10..b9996a3b4d3 100644 --- a/chromium/pdf/pdfium/pdfium_engine.h +++ b/chromium/pdf/pdfium/pdfium_engine.h @@ -383,14 +383,14 @@ class PDFiumEngine : public PDFEngine, // Search a page using PDFium's methods. Doesn't work with unicode. This // function is just kept arount in case PDFium code is fixed. - void SearchUsingPDFium(const base::string16& term, + void SearchUsingPDFium(const std::u16string& term, bool case_sensitive, bool first_search, int character_to_start_searching_from, int current_page); // Search a page ourself using ICU. - void SearchUsingICU(const base::string16& term, + void SearchUsingICU(const std::u16string& term, bool case_sensitive, bool first_search, int character_to_start_searching_from, @@ -406,8 +406,8 @@ class PDFiumEngine : public PDFEngine, bool OnChar(const KeyboardInputEvent& event); // Decide what cursor should be displayed. - PP_CursorType_Dev DetermineCursorType(PDFiumPage::Area area, - int form_type) const; + ui::mojom::CursorType DetermineCursorType(PDFiumPage::Area area, + int form_type) const; bool ExtendSelection(int page_index, int char_index); diff --git a/chromium/pdf/pdfium/pdfium_engine_exports.cc b/chromium/pdf/pdfium/pdfium_engine_exports.cc index 4234d87cc26..780361bab26 100644 --- a/chromium/pdf/pdfium/pdfium_engine_exports.cc +++ b/chromium/pdf/pdfium/pdfium_engine_exports.cc @@ -153,7 +153,7 @@ base::Value RecursiveGetStructTree(FPDF_STRUCTELEMENT struct_elem) { if (children_count <= 0) return base::Value(base::Value::Type::NONE); - base::Optional opt_type = + base::Optional opt_type = CallPDFiumWideStringBufferApiAndReturnOptional( base::BindRepeating(FPDF_StructElement_GetType, struct_elem), true); if (!opt_type) @@ -162,14 +162,14 @@ base::Value RecursiveGetStructTree(FPDF_STRUCTELEMENT struct_elem) { base::Value result(base::Value::Type::DICTIONARY); result.SetStringKey("type", *opt_type); - base::Optional opt_alt = + base::Optional opt_alt = CallPDFiumWideStringBufferApiAndReturnOptional( base::BindRepeating(FPDF_StructElement_GetAltText, struct_elem), true); if (opt_alt) result.SetStringKey("alt", *opt_alt); - base::Optional opt_lang = + base::Optional opt_lang = CallPDFiumWideStringBufferApiAndReturnOptional( base::BindRepeating(FPDF_StructElement_GetLang, struct_elem), true); if (opt_lang) diff --git a/chromium/pdf/pdfium/pdfium_engine_unittest.cc b/chromium/pdf/pdfium/pdfium_engine_unittest.cc index 8df1438ebcf..cf976dc1374 100644 --- a/chromium/pdf/pdfium/pdfium_engine_unittest.cc +++ b/chromium/pdf/pdfium/pdfium_engine_unittest.cc @@ -22,7 +22,7 @@ #include "pdf/ppapi_migration/input_event_conversions.h" #include "pdf/test/test_client.h" #include "pdf/test/test_document_loader.h" -#include "pdf/thumbnail.h" +#include "pdf/ui/thumbnail.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/gfx/geometry/point.h" diff --git a/chromium/pdf/pdfium/pdfium_form_filler.cc b/chromium/pdf/pdfium/pdfium_form_filler.cc index b0c57366af4..b2ac56ae874 100644 --- a/chromium/pdf/pdfium/pdfium_form_filler.cc +++ b/chromium/pdf/pdfium/pdfium_form_filler.cc @@ -10,6 +10,7 @@ #include "base/bind.h" #include "base/feature_list.h" +#include "base/location.h" #include "base/strings/string_number_conversions.h" #include "base/strings/utf_string_conversions.h" #include "pdf/pdf_features.h" @@ -25,7 +26,7 @@ namespace { int g_last_timer_id = 0; std::string WideStringToString(FPDF_WIDESTRING wide_string) { - return base::UTF16ToUTF8(reinterpret_cast(wide_string)); + return base::UTF16ToUTF8(reinterpret_cast(wide_string)); } } // namespace @@ -610,8 +611,8 @@ int PDFiumFormFiller::Form_Response(IPDF_JSPLATFORM* param, PDFiumEngine* engine = GetEngine(param); std::string rv = engine->client_->Prompt(question_str, default_str); - base::string16 rv_16 = base::UTF8ToUTF16(rv); - int rv_bytes = rv_16.size() * sizeof(base::char16); + std::u16string rv_16 = base::UTF8ToUTF16(rv); + int rv_bytes = rv_16.size() * sizeof(char16_t); if (response) { int bytes_to_copy = rv_bytes < length ? rv_bytes : length; memcpy(response, rv_16.c_str(), bytes_to_copy); diff --git a/chromium/pdf/pdfium/pdfium_page.cc b/chromium/pdf/pdfium/pdfium_page.cc index b809e442904..cfbaa0a5767 100644 --- a/chromium/pdf/pdfium/pdfium_page.cc +++ b/chromium/pdf/pdfium/pdfium_page.cc @@ -27,7 +27,7 @@ #include "pdf/pdfium/pdfium_engine.h" #include "pdf/pdfium/pdfium_unsupported_features.h" #include "pdf/ppapi_migration/geometry_conversions.h" -#include "pdf/thumbnail.h" +#include "pdf/ui/thumbnail.h" #include "ppapi/c/private/ppb_pdf.h" #include "printing/units.h" #include "third_party/pdfium/public/cpp/fpdf_scopers.h" @@ -847,10 +847,10 @@ PDFiumPage::Area PDFiumPage::FormTypeToArea(int form_type) { } } -base::char16 PDFiumPage::GetCharAtIndex(int index) { +char16_t PDFiumPage::GetCharAtIndex(int index) { if (!available_) return L'\0'; - return static_cast(FPDFText_GetUnicode(GetTextPage(), index)); + return char16_t{FPDFText_GetUnicode(GetTextPage(), index)}; } int PDFiumPage::GetCharCount() { @@ -879,12 +879,10 @@ PDFiumPage::Area PDFiumPage::GetDestinationTarget(FPDF_DEST destination, GetPageDestinationTarget(destination, &x, &y, &target->zoom); if (x) { - target->x_in_pixels = - TransformPageToScreenX(PreProcessInPageCoordX(x.value())); + target->x_in_pixels = PreProcessAndTransformInPageCoordX(x.value()); } if (y) { - target->y_in_pixels = - TransformPageToScreenY(PreProcessInPageCoordY(y.value())); + target->y_in_pixels = PreProcessAndTransformInPageCoordY(y.value()); } return DOCLINK_AREA; @@ -920,16 +918,17 @@ void PDFiumPage::GetPageDestinationTarget(FPDF_DEST destination, *zoom_value = zoom; } -float PDFiumPage::PreProcessInPageCoordX(float x) { +float PDFiumPage::PreProcessAndTransformInPageCoordX(float x) { // If `x` < 0, scroll to the left side of the page. - // If `x` > width, scroll to the right side of the page. - return std::max(std::min(x, FPDF_GetPageWidthF(GetPage())), 0); + // If `x` > page width, scroll to the right side of the page. + return TransformPageToScreenX( + std::max(std::min(x, FPDF_GetPageWidthF(GetPage())), 0.0f)); } -float PDFiumPage::PreProcessInPageCoordY(float y) { +float PDFiumPage::PreProcessAndTransformInPageCoordY(float y) { // If `y` < 0, it is a valid input, no extra handling is needed. - // If `y` > height, scroll to the top of the page. - return std::min(y, FPDF_GetPageHeightF(GetPage())); + // If `y` > page height, scroll to the top of the page. + return TransformPageToScreenY(std::min(y, FPDF_GetPageHeightF(GetPage()))); } gfx::PointF PDFiumPage::TransformPageToScreenXY(const gfx::PointF& xy) { @@ -1008,10 +1007,10 @@ void PDFiumPage::PopulateWebLinks() { for (int i = 0; i < count; ++i) { // WARNING: FPDFLink_GetURL() is not compatible with // CallPDFiumWideStringBufferApi(). - base::string16 url; + std::u16string url; int url_length = FPDFLink_GetURL(links.get(), i, nullptr, 0); if (url_length > 0) { - PDFiumAPIStringBufferAdapter api_string_adapter( + PDFiumAPIStringBufferAdapter api_string_adapter( &url, url_length, true); unsigned short* data = reinterpret_cast(api_string_adapter.GetData()); diff --git a/chromium/pdf/pdfium/pdfium_page.h b/chromium/pdf/pdfium/pdfium_page.h index 41bbd6c43d6..7be403a785c 100644 --- a/chromium/pdf/pdfium/pdfium_page.h +++ b/chromium/pdf/pdfium/pdfium_page.h @@ -14,7 +14,6 @@ #include "base/callback_forward.h" #include "base/gtest_prod_util.h" #include "base/optional.h" -#include "base/strings/string16.h" #include "pdf/page_orientation.h" #include "pdf/pdf_engine.h" #include "ppapi/cpp/private/pdf.h" @@ -126,9 +125,10 @@ class PDFiumPage { base::Optional* zoom_value); // For a named destination with "XYZ" view fit type, pre-processes the in-page - // x/y coordinate in case it's out of the range of the page dimension. - float PreProcessInPageCoordX(float x); - float PreProcessInPageCoordY(float y); + // x/y coordinate in case it's out of the range of the page dimension. Then + // transform it to a screen coordinate. + float PreProcessAndTransformInPageCoordX(float x); + float PreProcessAndTransformInPageCoordY(float y); // Transforms an (x, y) position in page coordinates to screen coordinates. gfx::PointF TransformPageToScreenXY(const gfx::PointF& xy); @@ -153,7 +153,7 @@ class PDFiumPage { static Area FormTypeToArea(int form_type); // Gets the character at the given index. - base::char16 GetCharAtIndex(int index); + char16_t GetCharAtIndex(int index); // Gets the number of characters in the page. int GetCharCount(); diff --git a/chromium/pdf/pdfium/pdfium_page_unittest.cc b/chromium/pdf/pdfium/pdfium_page_unittest.cc index 2ecb25573a4..98a329d71e5 100644 --- a/chromium/pdf/pdfium/pdfium_page_unittest.cc +++ b/chromium/pdf/pdfium/pdfium_page_unittest.cc @@ -21,7 +21,7 @@ #include "pdf/pdfium/pdfium_test_base.h" #include "pdf/ppapi_migration/geometry_conversions.h" #include "pdf/test/test_client.h" -#include "pdf/thumbnail.h" +#include "pdf/ui/thumbnail.h" #include "ppapi/c/private/ppb_pdf.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/pdfium/public/fpdf_formfill.h" diff --git a/chromium/pdf/pdfium/pdfium_range.cc b/chromium/pdf/pdfium/pdfium_range.cc index 437b478b412..eda743c256b 100644 --- a/chromium/pdf/pdfium/pdfium_range.cc +++ b/chromium/pdf/pdfium/pdfium_range.cc @@ -25,7 +25,7 @@ void AdjustForBackwardsRange(int* index, int* count) { } // namespace -bool IsIgnorableCharacter(base::char16 c) { +bool IsIgnorableCharacter(char16_t c) { return (c == kZeroWidthSpace) || (c == kPDFSoftHyphenMarker); } @@ -94,16 +94,16 @@ const std::vector& PDFiumRange::GetScreenRects( return cached_screen_rects_; } -base::string16 PDFiumRange::GetText() const { +std::u16string PDFiumRange::GetText() const { int index = char_index_; int count = char_count_; - base::string16 rv; + std::u16string rv; if (count == 0) return rv; AdjustForBackwardsRange(&index, &count); if (count > 0) { - PDFiumAPIStringBufferAdapter api_string_adapter(&rv, count, + PDFiumAPIStringBufferAdapter api_string_adapter(&rv, count, false); unsigned short* data = reinterpret_cast(api_string_adapter.GetData()); @@ -111,7 +111,7 @@ base::string16 PDFiumRange::GetText() const { api_string_adapter.Close(written); } - base::EraseIf(rv, [](base::char16 c) { return IsIgnorableCharacter(c); }); + base::EraseIf(rv, [](char16_t c) { return IsIgnorableCharacter(c); }); return rv; } diff --git a/chromium/pdf/pdfium/pdfium_range.h b/chromium/pdf/pdfium/pdfium_range.h index 75512ec124a..17a5dbd24df 100644 --- a/chromium/pdf/pdfium/pdfium_range.h +++ b/chromium/pdf/pdfium/pdfium_range.h @@ -8,7 +8,6 @@ #include #include -#include "base/strings/string16.h" #include "pdf/page_orientation.h" #include "pdf/pdfium/pdfium_page.h" #include "ui/gfx/geometry/point.h" @@ -16,13 +15,13 @@ namespace chrome_pdf { -constexpr base::char16 kZeroWidthSpace = 0x200B; -constexpr base::char16 kPDFSoftHyphenMarker = 0xFFFE; +constexpr char16_t kZeroWidthSpace = 0x200B; +constexpr char16_t 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); +bool IsIgnorableCharacter(char16_t c); // Describes location of a string of characters. class PDFiumRange { @@ -46,7 +45,7 @@ class PDFiumRange { PageOrientation orientation) const; // Gets the string of characters in this range. - base::string16 GetText() const; + std::u16string GetText() const; private: PDFiumPage* page_; diff --git a/chromium/pdf/post_message_receiver.cc b/chromium/pdf/post_message_receiver.cc index 1e978f81ebd..6ea632030f3 100644 --- a/chromium/pdf/post_message_receiver.cc +++ b/chromium/pdf/post_message_receiver.cc @@ -8,6 +8,7 @@ #include #include "base/bind.h" +#include "base/location.h" #include "base/memory/scoped_refptr.h" #include "base/memory/weak_ptr.h" #include "base/notreached.h" @@ -49,8 +50,19 @@ PostMessageReceiver::PostMessageReceiver( gin::ObjectTemplateBuilder PostMessageReceiver::GetObjectTemplateBuilder( v8::Isolate* isolate) { + // The function template needs to be created with a repeating callback instead + // of a member function pointer (MFP). Gin expects the first parameter for a + // callback to a MFP to be the JavaScript `this` object corresponding to this + // scriptable object exposed through Blink. However, the actual receiving + // object for a plugins is a HTMLEmbedElement and Blink internally forwards + // the parameters to this scriptable object. + // + // `base::Unretained(this)` is safe to use because the callback will only be + // called within the lifetime of the wrapped PostMessageReceiver object. return gin::Wrappable::GetObjectTemplateBuilder(isolate) - .SetMethod("postMessage", &PostMessageReceiver::PostMessage); + .SetMethod("postMessage", + base::BindRepeating(&PostMessageReceiver::PostMessage, + base::Unretained(this))); } const char* PostMessageReceiver::GetTypeName() { diff --git a/chromium/pdf/post_message_sender.cc b/chromium/pdf/post_message_sender.cc index 057cef6e064..8815223a868 100644 --- a/chromium/pdf/post_message_sender.cc +++ b/chromium/pdf/post_message_sender.cc @@ -37,6 +37,7 @@ void PostMessageSender::Post(base::Value message) { v8::Local context = container_->GetDocument().GetFrame()->MainWorldScriptContext(); DCHECK_EQ(isolate_, context->GetIsolate()); + v8::Context::Scope context_scope(context); if (!v8_value_converter_) v8_value_converter_ = content::V8ValueConverter::Create(); diff --git a/chromium/pdf/ppapi_migration/geometry_conversions.cc b/chromium/pdf/ppapi_migration/geometry_conversions.cc index af0e1b5f10c..a288e30f609 100644 --- a/chromium/pdf/ppapi_migration/geometry_conversions.cc +++ b/chromium/pdf/ppapi_migration/geometry_conversions.cc @@ -33,11 +33,6 @@ PP_Rect PPRectFromRect(const gfx::Rect& rect) { return PP_MakeRectFromXYWH(rect.x(), rect.y(), rect.width(), rect.height()); } -gfx::RectF RectFFromPPFloatRect(const PP_FloatRect& pp_rect) { - return gfx::RectF(pp_rect.point.x, pp_rect.point.y, pp_rect.size.width, - pp_rect.size.height); -} - PP_FloatRect PPFloatRectFromRectF(const gfx::RectF& rect) { return PP_MakeFloatRectFromXYWH(rect.x(), rect.y(), rect.width(), rect.height()); diff --git a/chromium/pdf/ppapi_migration/geometry_conversions.h b/chromium/pdf/ppapi_migration/geometry_conversions.h index 12884c9f40f..2df70ddf862 100644 --- a/chromium/pdf/ppapi_migration/geometry_conversions.h +++ b/chromium/pdf/ppapi_migration/geometry_conversions.h @@ -28,7 +28,6 @@ gfx::PointF PointFFromPPFloatPoint(const PP_FloatPoint& pp_point); gfx::Rect RectFromPPRect(const PP_Rect& pp_rect); PP_Rect PPRectFromRect(const gfx::Rect& rect); -gfx::RectF RectFFromPPFloatRect(const PP_FloatRect& pp_rect); PP_FloatRect PPFloatRectFromRectF(const gfx::RectF& rect); gfx::Size SizeFromPPSize(const PP_Size& pp_size); diff --git a/chromium/pdf/ppapi_migration/geometry_conversions_unittest.cc b/chromium/pdf/ppapi_migration/geometry_conversions_unittest.cc index b17c64a9a33..0d0286b73a3 100644 --- a/chromium/pdf/ppapi_migration/geometry_conversions_unittest.cc +++ b/chromium/pdf/ppapi_migration/geometry_conversions_unittest.cc @@ -58,16 +58,6 @@ TEST(GeometryConversionsTest, PPRectFromRect) { EXPECT_EQ(pp_c_rect.size.height, 3); } -TEST(GeometryConversionsTest, RectFFromPPFloatRect) { - gfx::RectF rect = - RectFFromPPFloatRect(pp::FloatRect(-1.0f, 2.1f, 3.2f, 4.3f)); - EXPECT_EQ(rect, gfx::RectF(-1.0f, 2.1f, 3.2f, 4.3f)); - - rect = - RectFFromPPFloatRect(PP_MakeFloatRectFromXYWH(2.9f, -1.8f, 4.7f, 3.6f)); - EXPECT_EQ(rect, gfx::RectF(2.9f, -1.8f, 4.7f, 3.6f)); -} - TEST(GeometryConversionsTest, PPFloatRectFromRectF) { pp::FloatRect pp_cpp_rect = PPFloatRectFromRectF(gfx::RectF(-1.1f, 2.3f, 3.5f, 4.7f)); diff --git a/chromium/pdf/ppapi_migration/graphics.cc b/chromium/pdf/ppapi_migration/graphics.cc index aaf1efb3fa7..2be1b66531d 100644 --- a/chromium/pdf/ppapi_migration/graphics.cc +++ b/chromium/pdf/ppapi_migration/graphics.cc @@ -6,10 +6,12 @@ #include +#include #include #include "base/callback.h" #include "base/check_op.h" +#include "base/location.h" #include "base/memory/ptr_util.h" #include "base/threading/sequenced_task_runner_handle.h" #include "pdf/ppapi_migration/callback.h" @@ -21,6 +23,7 @@ #include "ppapi/cpp/point.h" #include "ppapi/cpp/rect.h" #include "third_party/skia/include/core/SkCanvas.h" +#include "ui/gfx/blit.h" #include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/size.h" #include "ui/gfx/geometry/vector2d.h" @@ -81,22 +84,30 @@ void PepperGraphics::SetLayerTransform(float scale, } // static -std::unique_ptr SkiaGraphics::Create(const gfx::Size& size) { - auto graphics = base::WrapUnique(new SkiaGraphics(size)); +std::unique_ptr SkiaGraphics::Create(Client* client, + const gfx::Size& size) { + auto graphics = base::WrapUnique(new SkiaGraphics(client, size)); if (!graphics->skia_graphics_) return nullptr; return graphics; } -SkiaGraphics::SkiaGraphics(const gfx::Size& size) +SkiaGraphics::SkiaGraphics(Client* client, const gfx::Size& size) : Graphics(size), + client_(client), skia_graphics_( SkSurface::MakeRasterN32Premul(size.width(), size.height())) {} SkiaGraphics::~SkiaGraphics() = default; bool SkiaGraphics::Flush(ResultCallback callback) { + sk_sp snapshot = skia_graphics_->makeImageSnapshot(); + skia_graphics_->getCanvas()->drawImage( + snapshot.get(), /*x=*/0, /*y=*/0, SkSamplingOptions(), /*paint=*/nullptr); + + client_->UpdateSnapshot(std::move(snapshot)); + base::SequencedTaskRunnerHandle::Get()->PostTask( FROM_HERE, base::BindOnce(std::move(callback), 0)); return true; @@ -110,7 +121,14 @@ void SkiaGraphics::PaintImage(const Image& image, const gfx::Rect& src_rect) { } void SkiaGraphics::Scroll(const gfx::Rect& clip, const gfx::Vector2d& amount) { - NOTIMPLEMENTED_LOG_ONCE(); + // If we are being asked to scroll by more than the graphics' rect size, just + // ignore the scroll command. + if (std::abs(amount.x()) >= skia_graphics_->width() || + std::abs(amount.y()) >= skia_graphics_->height()) { + return; + } + + gfx::ScrollCanvas(skia_graphics_->getCanvas(), clip, amount); } void SkiaGraphics::SetScale(float scale) { @@ -123,8 +141,4 @@ void SkiaGraphics::SetLayerTransform(float scale, NOTIMPLEMENTED_LOG_ONCE(); } -sk_sp SkiaGraphics::CreateSnapshot() { - return skia_graphics_->makeImageSnapshot(); -} - } // namespace chrome_pdf diff --git a/chromium/pdf/ppapi_migration/graphics.h b/chromium/pdf/ppapi_migration/graphics.h index ea266ee3a17..6b1f95cf2e3 100644 --- a/chromium/pdf/ppapi_migration/graphics.h +++ b/chromium/pdf/ppapi_migration/graphics.h @@ -5,11 +5,16 @@ #ifndef PDF_PPAPI_MIGRATION_GRAPHICS_H_ #define PDF_PPAPI_MIGRATION_GRAPHICS_H_ +#include + #include "pdf/ppapi_migration/callback.h" #include "ppapi/cpp/graphics_2d.h" +#include "third_party/skia/include/core/SkRefCnt.h" #include "third_party/skia/include/core/SkSurface.h" #include "ui/gfx/geometry/size.h" +class SkImage; + namespace gfx { class Point; class Rect; @@ -84,7 +89,19 @@ class PepperGraphics final : public Graphics { // A Skia graphics device. class SkiaGraphics final : public Graphics { public: - static std::unique_ptr Create(const gfx::Size& size); + // A client interface that needs to be registered when SkiaGraphics is + // created. + class Client { + public: + virtual ~Client() = default; + + // Updates the client with the latest snapshot created by Flush(). + virtual void UpdateSnapshot(sk_sp snapshot) = 0; + }; + + // `client` must remain valid throughout the lifespan of the object. + static std::unique_ptr Create(Client* client, + const gfx::Size& size); ~SkiaGraphics() override; @@ -98,10 +115,11 @@ class SkiaGraphics final : public Graphics { const gfx::Point& origin, const gfx::Vector2d& translate) override; - sk_sp CreateSnapshot(); - private: - explicit SkiaGraphics(const gfx::Size& size); + explicit SkiaGraphics(Client* client, const gfx::Size& size); + + // Unowned pointer. The client is required to outlive this object. + Client* client_; sk_sp skia_graphics_; }; diff --git a/chromium/pdf/ppapi_migration/graphics_unittest.cc b/chromium/pdf/ppapi_migration/graphics_unittest.cc index 33cf594f165..11029f85f79 100644 --- a/chromium/pdf/ppapi_migration/graphics_unittest.cc +++ b/chromium/pdf/ppapi_migration/graphics_unittest.cc @@ -6,13 +6,18 @@ #include +#include "base/callback_helpers.h" +#include "base/test/task_environment.h" #include "cc/test/pixel_comparator.h" #include "cc/test/pixel_test_utils.h" #include "pdf/ppapi_migration/bitmap.h" +#include "pdf/ppapi_migration/callback.h" #include "pdf/ppapi_migration/image.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/skia/include/core/SkCanvas.h" +#include "third_party/skia/include/core/SkImage.h" #include "third_party/skia/include/core/SkImageInfo.h" +#include "third_party/skia/include/core/SkRefCnt.h" #include "third_party/skia/include/core/SkSize.h" #include "third_party/skia/include/core/SkSurface.h" #include "ui/gfx/geometry/rect.h" @@ -20,8 +25,20 @@ #include "ui/gfx/skia_util.h" namespace chrome_pdf { + namespace { +struct FakeSkiaGraphicsClient : public SkiaGraphics::Client { + FakeSkiaGraphicsClient() = default; + ~FakeSkiaGraphicsClient() override = default; + + void UpdateSnapshot(sk_sp new_snapshot) override { + snapshot = std::move(new_snapshot); + } + + sk_sp snapshot; +}; + Image CreateSourceImage(const SkISize& src_size) { SkBitmap bitmap = CreateN32PremulSkBitmap(src_size); bitmap.eraseColor(SK_ColorRED); @@ -35,35 +52,112 @@ SkBitmap GenerateExpectedBitmap(const SkISize& graphics_size, return bitmap; } -void TestPaintImageResult(const SkISize& graphics_size, - const SkISize& src_size, - const gfx::Rect& paint_rect, - const SkIRect& overlapped_rect) { - auto graphics = SkiaGraphics::Create(gfx::SkISizeToSize(graphics_size)); - ASSERT_TRUE(graphics); - - // Create snapshots as SkImage and SkBitmap after painting. - graphics->PaintImage(CreateSourceImage(src_size), paint_rect); - sk_sp snapshot = graphics->CreateSnapshot(); - SkBitmap snapshot_bitmap; - ASSERT_TRUE(snapshot->asLegacyBitmap(&snapshot_bitmap)); - - // Verify snapshot dimensions. - EXPECT_EQ(snapshot->dimensions(), graphics_size) - << snapshot->width() << " x " << snapshot->height() - << " != " << graphics_size.width() << " x " << graphics_size.height(); - - // Verify the snapshot matches the expected result. - const SkBitmap expected_bitmap = - GenerateExpectedBitmap(graphics_size, overlapped_rect); - EXPECT_TRUE( - cc::MatchesBitmap(snapshot_bitmap, expected_bitmap, - cc::ExactPixelComparator(/*discard_alpha=*/false))) - << "SkBitmap comparison failed for graphics size of " - << graphics_size.width() << " x " << graphics_size.height(); +// Creates a nonuniform SkBitmap with given `width` and `height`, such +// that scrolling will cause a noticeable change to the bitmap. Returns an +// empty SkBitmap if either `width` or `height` is less than 4. +SkBitmap CreateNonuniformBitmap(int width, int height) { + if (width < 4 || height < 4) + return SkBitmap(); + + SkBitmap bitmap = CreateN32PremulSkBitmap(SkISize::Make(width, height)); + bitmap.eraseColor(SK_ColorRED); + bitmap.erase(SK_ColorGREEN, {1, 1, width - 1, height - 2}); + bitmap.erase(SK_ColorBLACK, {2, 3, 1, 2}); + return bitmap; +} + +} // namespace + +class SkiaGraphicsTest : public testing::Test { + protected: + void TestPaintImageResult(const SkISize& graphics_size, + const SkISize& src_size, + const gfx::Rect& paint_rect, + const SkIRect& overlapped_rect) { + graphics_ = + SkiaGraphics::Create(&client_, gfx::SkISizeToSize(graphics_size)); + ASSERT_TRUE(graphics_); + + // Create snapshots as SkImage and SkBitmap after painting. + graphics_->PaintImage(CreateSourceImage(src_size), paint_rect); + graphics_->Flush(base::DoNothing()); + SkBitmap snapshot_bitmap; + ASSERT_TRUE(client_.snapshot->asLegacyBitmap(&snapshot_bitmap)); + + // Verify snapshot dimensions. + EXPECT_EQ(client_.snapshot->dimensions(), graphics_size) + << client_.snapshot->width() << " x " << client_.snapshot->height() + << " != " << graphics_size.width() << " x " << graphics_size.height(); + + // Verify the snapshot matches the expected result. + const SkBitmap expected_bitmap = + GenerateExpectedBitmap(graphics_size, overlapped_rect); + EXPECT_TRUE( + cc::MatchesBitmap(snapshot_bitmap, expected_bitmap, + cc::ExactPixelComparator(/*discard_alpha=*/false))) + << "SkBitmap comparison failed for graphics size of " + << graphics_size.width() << " x " << graphics_size.height(); + } + + FakeSkiaGraphicsClient client_; + + std::unique_ptr graphics_; + + private: + base::test::TaskEnvironment task_environment_; +}; + +class SkiaGraphicsScrollTest : public SkiaGraphicsTest { + protected: + static constexpr gfx::Rect kGraphicsRect = gfx::Rect(4, 5); + + // Initializes `initial_bitmap_` and `graphics_` before scrolling tests. + void SetUp() override { + graphics_ = SkiaGraphics::Create(&client_, kGraphicsRect.size()); + ASSERT_TRUE(graphics_); + + // Paint a nonuniform SkBitmap to graphics. + initial_bitmap_ = + CreateNonuniformBitmap(kGraphicsRect.width(), kGraphicsRect.height()); + graphics_->PaintImage(Image(initial_bitmap_), kGraphicsRect); + graphics_->Flush(base::DoNothing()); + SkBitmap initial_snapshot; + ASSERT_TRUE(client_.snapshot->asLegacyBitmap(&initial_snapshot)); + ASSERT_TRUE(cc::MatchesBitmap(initial_snapshot, initial_bitmap_, + cc::ExactPixelComparator(false))); + } + + // Resets the canvas with `initial_bitmap_`, then scrolls it by + // `scroll_amount`. + void ResetAndScroll(const gfx::Vector2d& scroll_amount) { + if (!graphics_) + return; + + graphics_->PaintImage(Image(initial_bitmap_), kGraphicsRect); + graphics_->Scroll(kGraphicsRect, scroll_amount); + graphics_->Flush(base::DoNothing()); + } + + SkBitmap initial_bitmap_; +}; + +// static +constexpr gfx::Rect SkiaGraphicsScrollTest::kGraphicsRect; + +TEST_F(SkiaGraphicsTest, Flush) { + graphics_ = SkiaGraphics::Create(&client_, gfx::Size(20, 20)); + ASSERT_TRUE(graphics_); + + // The client's snapshot is nullptr before flushing. + EXPECT_FALSE(client_.snapshot); + + EXPECT_TRUE(graphics_->Flush(base::DoNothing())); + + // The client's snapshot has changed after flushing. + EXPECT_TRUE(client_.snapshot); } -TEST(SkiaGraphicsTest, PaintImage) { +TEST_F(SkiaGraphicsTest, PaintImage) { struct PaintImageParams { // Size of the graphics to be painted on. SkISize graphics_size; @@ -95,5 +189,48 @@ TEST(SkiaGraphicsTest, PaintImage) { params.paint_rect, params.overlapped_rect); } -} // namespace +TEST_F(SkiaGraphicsScrollTest, InvalidScroll) { + static constexpr gfx::Vector2d kNoOpScrollAmounts[] = { + // Scroll to the edge of the graphics rect. + {kGraphicsRect.width(), 0}, + {-kGraphicsRect.width(), 0}, + {0, kGraphicsRect.height()}, + {0, -kGraphicsRect.height()}, + // Scroll outside the graphics rect. + {kGraphicsRect.width() + 1, 0}, + {-(kGraphicsRect.width() + 2), 0}, + {0, kGraphicsRect.height() + 3}, + {0, -(kGraphicsRect.height() + 4)}, + }; + + for (const auto& no_op_amount : kNoOpScrollAmounts) { + ResetAndScroll(no_op_amount); + SkBitmap snapshot; + ASSERT_TRUE(client_.snapshot->asLegacyBitmap(&snapshot)); + EXPECT_TRUE(cc::MatchesBitmap(snapshot, initial_bitmap_, + cc::ExactPixelComparator(false))) + << "SkBitmap comparison failed for scroll amount of " + << no_op_amount.ToString(); + } +} + +TEST_F(SkiaGraphicsScrollTest, Scroll) { + static constexpr gfx::Vector2d kValidScrollAmounts[] = { + {1, 0}, + {-2, 0}, + {0, 3}, + {0, -3}, + }; + + for (const auto& valid_amount : kValidScrollAmounts) { + ResetAndScroll(valid_amount); + SkBitmap snapshot; + ASSERT_TRUE(client_.snapshot->asLegacyBitmap(&snapshot)); + EXPECT_FALSE(cc::MatchesBitmap(snapshot, initial_bitmap_, + cc::ExactPixelComparator(false))) + << "The scroll amount of " << valid_amount.ToString() + << " failed to change the snapshot of `graphics_`"; + } +} + } // namespace chrome_pdf diff --git a/chromium/pdf/ppapi_migration/input_event_conversions.cc b/chromium/pdf/ppapi_migration/input_event_conversions.cc index 7c7b65d7fa6..0a84ca07300 100644 --- a/chromium/pdf/ppapi_migration/input_event_conversions.cc +++ b/chromium/pdf/ppapi_migration/input_event_conversions.cc @@ -8,8 +8,10 @@ #include "base/notreached.h" #include "pdf/ppapi_migration/geometry_conversions.h" +#include "ppapi/c/dev/pp_cursor_type_dev.h" #include "ppapi/cpp/input_event.h" #include "ppapi/cpp/var.h" +#include "ui/base/cursor/mojom/cursor_type.mojom-shared.h" #include "ui/gfx/geometry/point_conversions.h" namespace { @@ -217,4 +219,19 @@ TouchInputEvent GetTouchInputEvent(const pp::TouchInputEvent& event) { event.GetTouchCount(PP_TOUCHLIST_TYPE_TARGETTOUCHES)); } +PP_CursorType_Dev PPCursorTypeFromCursorType( + ui::mojom::CursorType cursor_type) { + switch (cursor_type) { + case ui::mojom::CursorType::kPointer: + return PP_CURSORTYPE_POINTER; + case ui::mojom::CursorType::kHand: + return PP_CURSORTYPE_HAND; + case ui::mojom::CursorType::kIBeam: + return PP_CURSORTYPE_IBEAM; + default: + NOTREACHED(); + return PP_CURSORTYPE_POINTER; + } +} + } // namespace chrome_pdf diff --git a/chromium/pdf/ppapi_migration/input_event_conversions.h b/chromium/pdf/ppapi_migration/input_event_conversions.h index 3116080fed2..a8b9065fe32 100644 --- a/chromium/pdf/ppapi_migration/input_event_conversions.h +++ b/chromium/pdf/ppapi_migration/input_event_conversions.h @@ -8,6 +8,8 @@ #include #include +#include "ppapi/c/dev/pp_cursor_type_dev.h" +#include "ui/base/cursor/mojom/cursor_type.mojom-forward.h" #include "ui/gfx/geometry/point.h" #include "ui/gfx/geometry/point_f.h" @@ -224,6 +226,8 @@ MouseInputEvent GetMouseInputEvent(const pp::MouseInputEvent& event); TouchInputEvent GetTouchInputEvent(const pp::TouchInputEvent& event); +PP_CursorType_Dev PPCursorTypeFromCursorType(ui::mojom::CursorType cursor_type); + } // namespace chrome_pdf #endif // PDF_PPAPI_MIGRATION_INPUT_EVENT_CONVERSIONS_H_ diff --git a/chromium/pdf/preview_mode_client.cc b/chromium/pdf/preview_mode_client.cc index 36de088cc02..3bd684560e8 100644 --- a/chromium/pdf/preview_mode_client.cc +++ b/chromium/pdf/preview_mode_client.cc @@ -11,17 +11,19 @@ #include #include "base/callback.h" -#include "base/location.h" #include "base/notreached.h" #include "base/time/time.h" #include "pdf/document_layout.h" #include "pdf/ppapi_migration/url_loader.h" #include "third_party/skia/include/core/SkColor.h" +#include "ui/base/cursor/mojom/cursor_type.mojom-shared.h" namespace chrome_pdf { PreviewModeClient::PreviewModeClient(Client* client) : client_(client) {} +PreviewModeClient::~PreviewModeClient() = default; + void PreviewModeClient::ProposeDocumentLayout(const DocumentLayout& layout) { // This will be invoked if the PreviewModeClient is used, which currently // occurs if and only if loading a non-PDF document with more than 1 page. @@ -56,7 +58,7 @@ void PreviewModeClient::NavigateTo(const std::string& url, NOTREACHED(); } -void PreviewModeClient::UpdateCursor(PP_CursorType_Dev cursor) { +void PreviewModeClient::UpdateCursor(ui::mojom::CursorType cursor_type) { NOTREACHED(); } @@ -124,8 +126,8 @@ std::unique_ptr PreviewModeClient::CreateUrlLoader() { } std::vector -PreviewModeClient::SearchString(const base::char16* string, - const base::char16* term, +PreviewModeClient::SearchString(const char16_t* string, + const char16_t* term, bool case_sensitive) { NOTREACHED(); return std::vector(); @@ -176,10 +178,10 @@ bool PreviewModeClient::IsValidLink(const std::string& url) { } void PreviewModeClient::ScheduleTaskOnMainThread( - base::TimeDelta delay, + const base::Location& from_here, ResultCallback callback, int32_t result, - const base::Location& from_here) { + base::TimeDelta delay) { NOTREACHED(); } diff --git a/chromium/pdf/preview_mode_client.h b/chromium/pdf/preview_mode_client.h index 0df963ac0c8..5e992ca7e90 100644 --- a/chromium/pdf/preview_mode_client.h +++ b/chromium/pdf/preview_mode_client.h @@ -11,14 +11,8 @@ #include #include "base/callback_forward.h" -#include "base/location.h" #include "pdf/pdf_engine.h" -namespace gfx { -class Rect; -class Vector2d; -} // namespace gfx - namespace chrome_pdf { // The interface that's provided to the print preview rendering engine. @@ -31,7 +25,7 @@ class PreviewModeClient : public PDFEngine::Client { }; explicit PreviewModeClient(Client* client); - ~PreviewModeClient() override {} + ~PreviewModeClient() override; // PDFEngine::Client implementation. void ProposeDocumentLayout(const DocumentLayout& layout) override; @@ -43,7 +37,7 @@ class PreviewModeClient : public PDFEngine::Client { void ScrollToPage(int page) override; void NavigateTo(const std::string& url, WindowOpenDisposition disposition) override; - void UpdateCursor(PP_CursorType_Dev cursor) override; + void UpdateCursor(ui::mojom::CursorType cursor_type) override; void UpdateTickMarks(const std::vector& tickmarks) override; void NotifyNumberOfFindResultsChanged(int total, bool final_result) override; void NotifySelectedFindResultChanged(int current_find_index) override; @@ -64,8 +58,8 @@ class PreviewModeClient : public PDFEngine::Client { const void* data, int length) override; std::unique_ptr CreateUrlLoader() override; - std::vector SearchString(const base::char16* string, - const base::char16* term, + std::vector SearchString(const char16_t* string, + const char16_t* term, bool case_sensitive) override; void DocumentLoadComplete() override; void DocumentLoadFailed() override; @@ -77,11 +71,10 @@ class PreviewModeClient : public PDFEngine::Client { void SetSelectedText(const std::string& selected_text) override; void SetLinkUnderCursor(const std::string& link_under_cursor) override; bool IsValidLink(const std::string& url) override; - void ScheduleTaskOnMainThread( - base::TimeDelta delay, - ResultCallback callback, - int32_t result, - const base::Location& from_here = base::Location::Current()) override; + void ScheduleTaskOnMainThread(const base::Location& from_here, + ResultCallback callback, + int32_t result, + base::TimeDelta delay) override; private: Client* const client_; diff --git a/chromium/pdf/thumbnail.cc b/chromium/pdf/thumbnail.cc deleted file mode 100644 index 2419e92c0be..00000000000 --- a/chromium/pdf/thumbnail.cc +++ /dev/null @@ -1,125 +0,0 @@ -// Copyright 2020 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/thumbnail.h" - -#include -#include - -#include "base/check.h" -#include "base/check_op.h" -#include "base/numerics/ranges.h" -#include "base/numerics/safe_math.h" -#include "third_party/skia/include/core/SkBitmap.h" -#include "third_party/skia/include/core/SkImageInfo.h" -#include "ui/gfx/geometry/size.h" - -namespace chrome_pdf { - -namespace { - -constexpr float kMinDevicePixelRatio = 0.25; -constexpr float kMaxDevicePixelRatio = 2; - -constexpr int kImageColorChannels = 4; - -// TODO(crbug.com/702993): Reevaluate the thumbnail size cap when the PDF -// component migrates off of PPAPI. -// The maximum thumbnail area is essentially arbitrary, but the value was chosen -// considering the fact that when sending array buffers through PPAPI, if the -// size of the data is over 256KiB, it gets sent using shared memory instead of -// IPC. Thumbnail sizes are capped at 255KiB to avoid the 256KiB threshold for -// images and their metadata, such as size. -constexpr int kMaxThumbnailPixels = 255 * 1024 / kImageColorChannels; - -// Maximum CSS dimensions are set to match UX specifications. -// These constants should be kept in sync with `PORTRAIT_WIDTH` and -// `LANDSCAPE_WIDTH` in -// chrome/browser/resources/pdf/elements/viewer-thumbnail.js. -constexpr int kMaxWidthPortraitPx = 108; -constexpr int kMaxWidthLandscapePx = 140; - -// PDF page size limits in default user space units, as defined by PDF 1.7 Annex -// C.2, "Architectural limits". -constexpr int kPdfPageMinDimension = 3; -constexpr int kPdfPageMaxDimension = 14400; -constexpr int kPdfMaxAspectRatio = kPdfPageMaxDimension / kPdfPageMinDimension; - -// Limit the proportions within PDF limits to handle pathological PDF pages. -gfx::Size LimitAspectRatio(gfx::Size page_size) { - // Bump up any lengths of 0 to 1. - page_size.SetToMax(gfx::Size(1, 1)); - - if (page_size.height() / page_size.width() > kPdfMaxAspectRatio) - return gfx::Size(kPdfPageMinDimension, kPdfPageMaxDimension); - if (page_size.width() / page_size.height() > kPdfMaxAspectRatio) - return gfx::Size(kPdfPageMaxDimension, kPdfPageMinDimension); - - return page_size; -} - -// Calculate the size of a thumbnail image in device pixels using |page_size| in -// any units and |device_pixel_ratio|. -gfx::Size CalculateBestFitSize(const gfx::Size& page_size, - float device_pixel_ratio) { - gfx::Size safe_page_size = LimitAspectRatio(page_size); - - // Return the larger of the unrotated and rotated sizes to over-sample the PDF - // page so that the thumbnail looks good in different orientations. - float scale_portrait = - static_cast(kMaxWidthPortraitPx) / - std::min(safe_page_size.width(), safe_page_size.height()); - float scale_landscape = - static_cast(kMaxWidthLandscapePx) / - std::max(safe_page_size.width(), safe_page_size.height()); - float scale = std::max(scale_portrait, scale_landscape) * device_pixel_ratio; - - // Using gfx::ScaleToFlooredSize() is fine because `scale` will not yield an - // empty size unless `device_pixel_ratio` is very small (close to 0). - // However, `device_pixel_ratio` support is limited to between 0.25 and 2. - gfx::Size scaled_size = gfx::ScaleToFlooredSize(safe_page_size, scale); - if (scaled_size.GetCheckedArea().ValueOrDefault(kMaxThumbnailPixels + 1) > - kMaxThumbnailPixels) { - // Recalculate `scale` to accommodate pixel size limit such that: - // (scale * safe_page_size.width()) * (scale * safe_page_size.height()) == - // kMaxThumbnailPixels; - scale = std::sqrt(static_cast(kMaxThumbnailPixels) / - safe_page_size.width() / safe_page_size.height()); - return gfx::ScaleToFlooredSize(safe_page_size, scale); - } - - return scaled_size; -} - -} // namespace - -Thumbnail::Thumbnail() = default; - -Thumbnail::Thumbnail(const gfx::Size& page_size, float device_pixel_ratio) { - DCHECK_GE(device_pixel_ratio, kMinDevicePixelRatio); - DCHECK_LE(device_pixel_ratio, kMaxDevicePixelRatio); - device_pixel_ratio_ = base::ClampToRange( - device_pixel_ratio, kMinDevicePixelRatio, kMaxDevicePixelRatio); - - const gfx::Size thumbnail_size_device_pixels = - CalculateBestFitSize(page_size, device_pixel_ratio_); - - // Note that can only hold data in RGBA format. It is the - // responsibility of the thumbnail's renderer to fill `bitmap_` with RGBA - // data. - const SkImageInfo info = - SkImageInfo::Make(thumbnail_size_device_pixels.width(), - thumbnail_size_device_pixels.height(), - kRGBA_8888_SkColorType, kPremul_SkAlphaType); - bool success = bitmap_.tryAllocPixels(info, info.minRowBytes()); - DCHECK(success); -} - -Thumbnail::Thumbnail(Thumbnail&& other) = default; - -Thumbnail& Thumbnail::operator=(Thumbnail&& other) = default; - -Thumbnail::~Thumbnail() = default; - -} // namespace chrome_pdf diff --git a/chromium/pdf/thumbnail.h b/chromium/pdf/thumbnail.h deleted file mode 100644 index d62a56a5091..00000000000 --- a/chromium/pdf/thumbnail.h +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2020 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_THUMBNAIL_H_ -#define PDF_THUMBNAIL_H_ - -#include "third_party/skia/include/core/SkBitmap.h" - -namespace gfx { -class Size; -} // namespace gfx - -namespace chrome_pdf { - -class Thumbnail final { - public: - Thumbnail(); - Thumbnail(const gfx::Size& page_size, float device_pixel_ratio); - Thumbnail(Thumbnail&& other); - Thumbnail& operator=(Thumbnail&& other); - ~Thumbnail(); - - SkBitmap& bitmap() { return bitmap_; } - - float device_pixel_ratio() const { return device_pixel_ratio_; } - - private: - // Raw image data of the thumbnail. - SkBitmap bitmap_; - - // Intended resolution of the thumbnail image. The dimensions of `bitmap_` - // are the dimensions of the thumbnail in CSS pixels multiplied by - // `device_pixel_ratio_`. - // Only values between 0.25 and 2 are supported. - float device_pixel_ratio_ = 1; -}; - -} // namespace chrome_pdf - -#endif // PDF_THUMBNAIL_H_ diff --git a/chromium/pdf/thumbnail_unittest.cc b/chromium/pdf/thumbnail_unittest.cc deleted file mode 100644 index 03a8ef286e5..00000000000 --- a/chromium/pdf/thumbnail_unittest.cc +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright 2020 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/thumbnail.h" - -#include "testing/gtest/include/gtest/gtest.h" -#include "ui/gfx/geometry/size.h" - -namespace chrome_pdf { - -namespace { - -constexpr float kDeviceToPixelLow = 1; -constexpr float kDeviceToPixelHigh = 2; - -struct BestFitSizeParams { - float device_pixel_ratio; - gfx::Size page_size; - gfx::Size expected_thumbnail_size; -}; - -void TestBestFitSize(const BestFitSizeParams& params) { - Thumbnail thumbnail(params.page_size, params.device_pixel_ratio); - EXPECT_EQ(gfx::Size(thumbnail.bitmap().width(), thumbnail.bitmap().height()), - params.expected_thumbnail_size) - << "Failed for page of size of " << params.page_size.ToString() - << " and device to pixel ratio of " << params.device_pixel_ratio; -} - -TEST(ThumbnailTest, CalculateBestFitSizeNormal) { - static constexpr BestFitSizeParams kBestFitSizeTestParams[] = { - {kDeviceToPixelLow, {612, 792}, {108, 140}}, // ANSI Letter - {kDeviceToPixelLow, {595, 842}, {108, 152}}, // ISO 216 A4 - {kDeviceToPixelLow, {200, 200}, {140, 140}}, // Square - {kDeviceToPixelLow, {1000, 200}, {540, 108}}, // Wide - {kDeviceToPixelLow, {200, 1000}, {108, 540}}, // Tall - {kDeviceToPixelLow, {1500, 50}, {1399, 46}}, // Super wide - {kDeviceToPixelLow, {50, 1500}, {46, 1399}}, // Super tall - {kDeviceToPixelHigh, {612, 792}, {216, 280}}, // ANSI Letter - {kDeviceToPixelHigh, {595, 842}, {214, 303}}, // ISO 216 A4 - {kDeviceToPixelHigh, {200, 200}, {255, 255}}, // Square - {kDeviceToPixelHigh, {1000, 200}, {571, 114}}, // Wide - {kDeviceToPixelHigh, {200, 1000}, {114, 571}}, // Tall - {kDeviceToPixelHigh, {1500, 50}, {1399, 46}}, // Super wide - {kDeviceToPixelHigh, {50, 1500}, {46, 1399}}, // Super tall - }; - - for (const auto& params : kBestFitSizeTestParams) - TestBestFitSize(params); -} - -TEST(ThumbnailTest, CalculateBestFitSizeLargeAspectRatio) { - static constexpr BestFitSizeParams kBestFitSizeTestParams[] = { - {kDeviceToPixelLow, {14400, 3}, {17701, 3}}, // PDF 1.7 widest - {kDeviceToPixelLow, {3, 14400}, {3, 17701}}, // PDF 1.7 tallest - {kDeviceToPixelLow, {0, 0}, {140, 140}}, // Empty - {kDeviceToPixelLow, {9999999, 1}, {17701, 3}}, // Very wide - {kDeviceToPixelLow, {1, 9999999}, {3, 17701}}, // Very tall - {kDeviceToPixelHigh, {14400, 3}, {17701, 3}}, // PDF 1.7 widest - {kDeviceToPixelHigh, {3, 14400}, {3, 17701}}, // PDF 1.7 tallest - {kDeviceToPixelHigh, {0, 0}, {255, 255}}, // Empty - {kDeviceToPixelHigh, {9999999, 1}, {17701, 3}}, // Very wide - {kDeviceToPixelHigh, {1, 9999999}, {3, 17701}}, // Very tall - }; - - for (const auto& params : kBestFitSizeTestParams) - TestBestFitSize(params); -} - -TEST(ThumbnailTest, CalculateBestFitSizeNoOverflow) { - static constexpr BestFitSizeParams kBestFitSizeTestParams[] = { - {kDeviceToPixelLow, {9999999, 9999999}, {140, 140}}, // Very large - {kDeviceToPixelHigh, {9999999, 9999999}, {255, 255}}, // Very large - }; - - for (const auto& params : kBestFitSizeTestParams) - TestBestFitSize(params); -} - -} // namespace - -} // namespace chrome_pdf diff --git a/chromium/pdf/ui/DEPS b/chromium/pdf/ui/DEPS index 4f43a0788fb..6f91b14b746 100644 --- a/chromium/pdf/ui/DEPS +++ b/chromium/pdf/ui/DEPS @@ -5,7 +5,7 @@ include_rules = [ ] specific_include_rules = { - "format_page_size_unittest.cc": [ + "document_properties_unittest.cc": [ "+ui/base/resource", ], } diff --git a/chromium/pdf/ui/README.md b/chromium/pdf/ui/README.md index dbf51ca10a7..666617eea1d 100644 --- a/chromium/pdf/ui/README.md +++ b/chromium/pdf/ui/README.md @@ -2,7 +2,3 @@ This directory contains utilities for supporting PDF Viewer features other than the main content area. - -TODO(crbug.com/1184342): Accordingly move more code into this directory. For -instance, code that supports the document properties dialog and thumbnails -belong in this directory. diff --git a/chromium/pdf/ui/document_properties.cc b/chromium/pdf/ui/document_properties.cc new file mode 100644 index 00000000000..87f7f83af45 --- /dev/null +++ b/chromium/pdf/ui/document_properties.cc @@ -0,0 +1,122 @@ +// Copyright 2021 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/ui/document_properties.h" + +#include + +#include "base/i18n/number_formatting.h" +#include "base/i18n/rtl.h" +#include "base/optional.h" +#include "base/strings/string_number_conversions.h" +#include "components/strings/grit/components_strings.h" +#include "pdf/document_metadata.h" +#include "printing/units.h" +#include "third_party/icu/source/i18n/unicode/ulocdata.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/gfx/geometry/size.h" + +using printing::kMicronsPerInch; +using printing::kPointsPerInch; + +namespace chrome_pdf { + +namespace { + +// Scales `length_points` to be in inches instead of points. +constexpr float ConvertPointsToInches(int length_points) { + constexpr float kInchesPerPoint = 1.0f / kPointsPerInch; + return length_points * kInchesPerPoint; +} + +// Scales `length_points` to be in millimeters instead of points. +constexpr float ConvertPointsToMillimeters(int length_points) { + constexpr float kMillimetersPerInch = 25.4f; + constexpr float kMillimetersPerPoint = kMillimetersPerInch / kPointsPerInch; + return length_points * kMillimetersPerPoint; +} + +// Formats a length given in points. The formatted length is in inches and +// contains two fractional digits. +std::u16string FormatLengthInInches(int length_points) { + return base::FormatDouble(ConvertPointsToInches(length_points), + /*fractional_digits=*/2); +} + +// Formats a length given in points. The formatted length is in millimeters and +// contains no fractional digits. +std::u16string FormatLengthInMillimeters(int length_points) { + return base::FormatDouble(ConvertPointsToMillimeters(length_points), + /*fractional_digits=*/0); +} + +// Returns the localized string for the orientation. +std::u16string GetOrientation(const gfx::Size& size) { + // TODO(crbug.com/1184345): Add a string for square sizes such that they are + // not displayed as "portrait". + return l10n_util::GetStringUTF16( + size.height() >= size.width() ? IDS_PDF_PROPERTIES_PAGE_SIZE_PORTRAIT + : IDS_PDF_PROPERTIES_PAGE_SIZE_LANDSCAPE); +} + +bool ShowInches() { + UErrorCode error_code = U_ZERO_ERROR; + UMeasurementSystem system = ulocdata_getMeasurementSystem( + base::i18n::GetConfiguredLocale().c_str(), &error_code); + + // On error, assume the units are SI. + return U_SUCCESS(error_code) && system == UMS_US; +} + +} // namespace + +std::u16string FormatPageSize(const base::Optional& size_points) { + if (!size_points.has_value()) + return l10n_util::GetStringUTF16(IDS_PDF_PROPERTIES_PAGE_SIZE_VARIABLE); + + // TODO(dhoss): Consider using `icu::number::NumberFormatter`. + if (ShowInches()) { + return l10n_util::GetStringFUTF16( + IDS_PDF_PROPERTIES_PAGE_SIZE_VALUE_INCH, + FormatLengthInInches(size_points.value().width()), + FormatLengthInInches(size_points.value().height()), + GetOrientation(size_points.value())); + } + + return l10n_util::GetStringFUTF16( + IDS_PDF_PROPERTIES_PAGE_SIZE_VALUE_MM, + FormatLengthInMillimeters(size_points.value().width()), + FormatLengthInMillimeters(size_points.value().height()), + GetOrientation(size_points.value())); +} + +std::string FormatPdfVersion(PdfVersion version) { + switch (version) { + case PdfVersion::k1_0: + return "1.0"; + case PdfVersion::k1_1: + return "1.1"; + case PdfVersion::k1_2: + return "1.2"; + case PdfVersion::k1_3: + return "1.3"; + case PdfVersion::k1_4: + return "1.4"; + case PdfVersion::k1_5: + return "1.5"; + case PdfVersion::k1_6: + return "1.6"; + case PdfVersion::k1_7: + return "1.7"; + case PdfVersion::k2_0: + return "2.0"; + case PdfVersion::kUnknown: + case PdfVersion::k1_8: // Not an actual version + return std::string(); + } + // The default case is excluded from the above switch statement to ensure that + // all supported versions are determinantly handled. +} + +} // namespace chrome_pdf diff --git a/chromium/pdf/ui/document_properties.h b/chromium/pdf/ui/document_properties.h new file mode 100644 index 00000000000..33bc17687c9 --- /dev/null +++ b/chromium/pdf/ui/document_properties.h @@ -0,0 +1,35 @@ +// Copyright 2021 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_UI_DOCUMENT_PROPERTIES_H_ +#define PDF_UI_DOCUMENT_PROPERTIES_H_ + +#include + +#include "base/optional.h" +#include "pdf/document_metadata.h" + +namespace gfx { +class Size; +} // namespace gfx + +namespace chrome_pdf { + +// Formats `size_points` of a page to a localized string suitable for display to +// the user. The returned string contains the dimensions and orientation of the +// page. The dimension units are set by the user's locale. Example return +// values: +// -> 210 x 297 mm (portrait) +// -> 11.00 x 8.50 in (landscape) +// +// Returns the string "Varies" if `size_points` is `base::nullopt`. +std::u16string FormatPageSize(const base::Optional& size_points); + +// Formats `version` to a string suitable for display to a user. Version numbers +// do not require localization. +std::string FormatPdfVersion(PdfVersion version); + +} // namespace chrome_pdf + +#endif // PDF_UI_DOCUMENT_PROPERTIES_H_ diff --git a/chromium/pdf/ui/document_properties_unittest.cc b/chromium/pdf/ui/document_properties_unittest.cc new file mode 100644 index 00000000000..173eff54790 --- /dev/null +++ b/chromium/pdf/ui/document_properties_unittest.cc @@ -0,0 +1,167 @@ +// Copyright 2021 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/ui/document_properties.h" + +#include + +#include "base/i18n/number_formatting.h" +#include "base/i18n/rtl.h" +#include "base/optional.h" +#include "components/strings/grit/components_strings.h" +#include "pdf/document_metadata.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "ui/base/resource/mock_resource_bundle_delegate.h" +#include "ui/base/resource/resource_bundle.h" +#include "ui/gfx/geometry/size.h" + +namespace chrome_pdf { + +namespace { + +using ::testing::Invoke; +using ::testing::IsEmpty; +using ::testing::NiceMock; + +bool GetPageSizeString(int message_id, std::u16string* value) { + switch (message_id) { + case IDS_PDF_PROPERTIES_PAGE_SIZE_VALUE_INCH: + *value = u"$1 × $2 in ($3)"; + break; + case IDS_PDF_PROPERTIES_PAGE_SIZE_VALUE_MM: + *value = u"$1 × $2 mm ($3)"; + break; + case IDS_PDF_PROPERTIES_PAGE_SIZE_PORTRAIT: + *value = u"portrait"; + break; + case IDS_PDF_PROPERTIES_PAGE_SIZE_LANDSCAPE: + *value = u"landscape"; + break; + case IDS_PDF_PROPERTIES_PAGE_SIZE_VARIABLE: + *value = u"Varies"; + break; + default: + return false; + } + + return true; +} + +class FormatPageSizeTest : public testing::Test { + protected: + void SetUp() override { + // TODO(crbug.com/1184524): Consider initializing a resource bundle instance + // for all tests in `pdf_unittests`. + // `pdf_unittests` does not have a resource bundle that needs to be restored + // at the end of the test. + ASSERT_FALSE(ui::ResourceBundle::HasSharedInstance()); + + ON_CALL(mock_resource_delegate_, GetLocalizedString) + .WillByDefault(Invoke(GetPageSizeString)); + + const std::string locale(GetLocale()); + ui::ResourceBundle::InitSharedInstanceWithLocale( + locale, &mock_resource_delegate_, + ui::ResourceBundle::DO_NOT_LOAD_COMMON_RESOURCES); + + if (!locale.empty()) { + base::i18n::SetICUDefaultLocale(locale); + base::ResetFormattersForTesting(); + } + } + + void TearDown() override { + ASSERT_TRUE(ui::ResourceBundle::HasSharedInstance()); + ui::ResourceBundle::CleanupSharedInstance(); + base::i18n::SetICUDefaultLocale(default_locale_); + base::ResetFormattersForTesting(); + } + + virtual std::string GetLocale() const { return std::string(); } + + private: + std::string default_locale_{base::i18n::GetConfiguredLocale()}; + NiceMock mock_resource_delegate_; +}; + +} // namespace + +TEST_F(FormatPageSizeTest, NoUniformSize) { + EXPECT_EQ(FormatPageSize(base::nullopt), u"Varies"); +} + +class FormatPageSizeMillimetersTest : public FormatPageSizeTest { + protected: + std::string GetLocale() const override { return "en_CA"; } +}; + +TEST_F(FormatPageSizeMillimetersTest, EmptySize) { + EXPECT_EQ(FormatPageSize(gfx::Size()), u"0 × 0 mm (portrait)"); +} + +TEST_F(FormatPageSizeMillimetersTest, Portrait) { + EXPECT_EQ(FormatPageSize(gfx::Size(100, 200)), u"35 × 71 mm (portrait)"); +} + +TEST_F(FormatPageSizeMillimetersTest, Landscape) { + EXPECT_EQ(FormatPageSize(gfx::Size(200, 100)), u"71 × 35 mm (landscape)"); +} + +TEST_F(FormatPageSizeMillimetersTest, Square) { + EXPECT_EQ(FormatPageSize(gfx::Size(100, 100)), u"35 × 35 mm (portrait)"); +} + +TEST_F(FormatPageSizeMillimetersTest, Large) { + EXPECT_EQ(FormatPageSize(gfx::Size(72000, 72000)), + u"25,400 × 25,400 mm (portrait)"); +} + +class FormatPageSizeMillimetersPeriodSeparatorTest : public FormatPageSizeTest { + protected: + std::string GetLocale() const override { return "de_DE"; } +}; + +TEST_F(FormatPageSizeMillimetersPeriodSeparatorTest, Large) { + EXPECT_EQ(FormatPageSize(gfx::Size(72000, 72000)), + u"25.400 × 25.400 mm (portrait)"); +} + +class FormatPageSizeInchesTest : public FormatPageSizeTest { + protected: + std::string GetLocale() const override { return "en_US"; } +}; + +TEST_F(FormatPageSizeInchesTest, EmptySize) { + EXPECT_EQ(FormatPageSize(gfx::Size()), u"0.00 × 0.00 in (portrait)"); +} + +TEST_F(FormatPageSizeInchesTest, Portrait) { + EXPECT_EQ(FormatPageSize(gfx::Size(100, 200)), u"1.39 × 2.78 in (portrait)"); +} + +TEST_F(FormatPageSizeInchesTest, Landscape) { + EXPECT_EQ(FormatPageSize(gfx::Size(200, 100)), u"2.78 × 1.39 in (landscape)"); +} + +TEST_F(FormatPageSizeInchesTest, Square) { + EXPECT_EQ(FormatPageSize(gfx::Size(100, 100)), u"1.39 × 1.39 in (portrait)"); +} + +TEST_F(FormatPageSizeInchesTest, Large) { + EXPECT_EQ(FormatPageSize(gfx::Size(72000, 72000)), + u"1,000.00 × 1,000.00 in (portrait)"); +} + +TEST(FormatPdfVersion, Valid) { + EXPECT_EQ(FormatPdfVersion(PdfVersion::k1_7), "1.7"); + EXPECT_EQ(FormatPdfVersion(PdfVersion::k2_0), "2.0"); +} + +TEST(FormatPdfVersion, Invalid) { + EXPECT_THAT(FormatPdfVersion(PdfVersion::kUnknown), IsEmpty()); + EXPECT_THAT(FormatPdfVersion(PdfVersion::k1_8), IsEmpty()); +} + +} // namespace chrome_pdf diff --git a/chromium/pdf/ui/file_name.cc b/chromium/pdf/ui/file_name.cc new file mode 100644 index 00000000000..9ed08466a64 --- /dev/null +++ b/chromium/pdf/ui/file_name.cc @@ -0,0 +1,25 @@ +// Copyright 2021 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/ui/file_name.h" + +#include + +#include "base/strings/utf_string_conversions.h" +#include "net/base/filename_util.h" +#include "url/gurl.h" + +namespace chrome_pdf { + +std::string GetFileNameForSaveFromUrl(const std::string& url) { + // Generate a file name. Unfortunately, MIME type can't be provided, since it + // requires IO. + std::u16string file_name = net::GetSuggestedFilename( + GURL(url), /*content_disposition=*/std::string(), + /*referrer_charset=*/std::string(), /*suggested_name=*/std::string(), + /*mime_type=*/std::string(), /*default_name=*/std::string()); + return base::UTF16ToUTF8(file_name); +} + +} // namespace chrome_pdf diff --git a/chromium/pdf/ui/file_name.h b/chromium/pdf/ui/file_name.h new file mode 100644 index 00000000000..c1bcd149f4d --- /dev/null +++ b/chromium/pdf/ui/file_name.h @@ -0,0 +1,17 @@ +// Copyright 2021 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_UI_FILE_NAME_H_ +#define PDF_UI_FILE_NAME_H_ + +#include + +namespace chrome_pdf { + +// Creates a file name for saving a PDF file, given the source URL. +std::string GetFileNameForSaveFromUrl(const std::string& url); + +} // namespace chrome_pdf + +#endif // PDF_UI_FILE_NAME_H_ diff --git a/chromium/pdf/ui/file_name_unittest.cc b/chromium/pdf/ui/file_name_unittest.cc new file mode 100644 index 00000000000..455837c7492 --- /dev/null +++ b/chromium/pdf/ui/file_name_unittest.cc @@ -0,0 +1,32 @@ +// Copyright 2021 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/ui/file_name.h" + +#include + +#include "testing/gtest/include/gtest/gtest.h" + +namespace chrome_pdf { + +TEST(FileNameTest, GetFileNameForSaveFromUrl) { + EXPECT_EQ("b.pdf", GetFileNameForSaveFromUrl("https://test/a/b.pdf")); + + // File extensions should be kept as-is. + EXPECT_EQ("b.hat", GetFileNameForSaveFromUrl("https://test/a/b.hat")); + + // Most escaped characters should be unescaped. + EXPECT_EQ("a b.pdf", GetFileNameForSaveFromUrl("https://test/%61%20b.pdf")); + + // Escaped file path delimiters and control codes should be replaced by a + // placeholder. + EXPECT_EQ("a_b_.pdf", GetFileNameForSaveFromUrl("https://test/a%2Fb%01.pdf")); + + // UTF-8 characters, including ones left escaped by UnescapeURLComponent() for + // security reasons, are allowed in file paths. + EXPECT_EQ("\xF0\x9F\x94\x92", + GetFileNameForSaveFromUrl("https://test/%F0%9F%94%92")); +} + +} // namespace chrome_pdf diff --git a/chromium/pdf/ui/format_page_size.cc b/chromium/pdf/ui/format_page_size.cc deleted file mode 100644 index fc4d21307a8..00000000000 --- a/chromium/pdf/ui/format_page_size.cc +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright 2021 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/ui/format_page_size.h" - -#include - -#include "base/i18n/number_formatting.h" -#include "base/i18n/rtl.h" -#include "base/optional.h" -#include "base/strings/string16.h" -#include "components/strings/grit/components_strings.h" -#include "printing/units.h" -#include "third_party/icu/source/i18n/unicode/ulocdata.h" -#include "ui/base/l10n/l10n_util.h" -#include "ui/gfx/geometry/size.h" - -using printing::kMicronsPerInch; -using printing::kPointsPerInch; - -namespace chrome_pdf { - -namespace { - -// Scales `length_points` to be in inches instead of points. -constexpr float ConvertPointsToInches(int length_points) { - constexpr float kInchesPerPoint = 1.0f / kPointsPerInch; - return length_points * kInchesPerPoint; -} - -// Scales `length_points` to be in millimeters instead of points. -constexpr float ConvertPointsToMillimeters(int length_points) { - constexpr float kMillimetersPerInch = 25.4f; - constexpr float kMillimetersPerPoint = kMillimetersPerInch / kPointsPerInch; - return length_points * kMillimetersPerPoint; -} - -// Formats a length given in points. The formatted length is in inches and -// contains two fractional digits. -base::string16 FormatLengthInInches(int length_points) { - return base::FormatDouble(ConvertPointsToInches(length_points), - /*fractional_digits=*/2); -} - -// Formats a length given in points. The formatted length is in millimeters and -// contains no fractional digits. -base::string16 FormatLengthInMillimeters(int length_points) { - return base::FormatDouble(ConvertPointsToMillimeters(length_points), - /*fractional_digits=*/0); -} - -// Returns the localized string for the orientation. -base::string16 GetOrientation(const gfx::Size& size) { - // TODO(crbug.com/1184345): Add a string for square sizes such that they are - // not displayed as "portrait". - return l10n_util::GetStringUTF16( - size.height() >= size.width() ? IDS_PDF_PROPERTIES_PAGE_SIZE_PORTRAIT - : IDS_PDF_PROPERTIES_PAGE_SIZE_LANDSCAPE); -} - -bool ShowInches() { - UErrorCode error_code = U_ZERO_ERROR; - UMeasurementSystem system = ulocdata_getMeasurementSystem( - base::i18n::GetConfiguredLocale().c_str(), &error_code); - - // On error, assume the units are SI. - return U_SUCCESS(error_code) && system == UMS_US; -} - -} // namespace - -base::string16 FormatPageSize(const base::Optional& size_points) { - if (!size_points.has_value()) - return l10n_util::GetStringUTF16(IDS_PDF_PROPERTIES_PAGE_SIZE_VARIABLE); - - // TODO(dhoss): Consider using `icu::number::NumberFormatter`. - if (ShowInches()) { - return l10n_util::GetStringFUTF16( - IDS_PDF_PROPERTIES_PAGE_SIZE_VALUE_INCH, - FormatLengthInInches(size_points.value().width()), - FormatLengthInInches(size_points.value().height()), - GetOrientation(size_points.value())); - } - - return l10n_util::GetStringFUTF16( - IDS_PDF_PROPERTIES_PAGE_SIZE_VALUE_MM, - FormatLengthInMillimeters(size_points.value().width()), - FormatLengthInMillimeters(size_points.value().height()), - GetOrientation(size_points.value())); -} - -} // namespace chrome_pdf diff --git a/chromium/pdf/ui/format_page_size.h b/chromium/pdf/ui/format_page_size.h deleted file mode 100644 index 64d09e145aa..00000000000 --- a/chromium/pdf/ui/format_page_size.h +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2021 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_UI_FORMAT_PAGE_SIZE_H_ -#define PDF_UI_FORMAT_PAGE_SIZE_H_ - -#include "base/optional.h" -#include "base/strings/string16.h" - -namespace gfx { -class Size; -} // namespace gfx - -namespace chrome_pdf { - -// Formats `size_points` of a page to a localized string suitable for display to -// the user. The returned string contains the dimensions and orientation of the -// page. The dimension units are set by the user's locale. Example return -// values: -// -> 210 x 297 mm (portrait) -// -> 11.00 x 8.50 in (landscape) -// -// Returns the string "Varies" if `size_points` is `base::nullopt`. -base::string16 FormatPageSize(const base::Optional& size_points); - -} // namespace chrome_pdf - -#endif // PDF_UI_FORMAT_PAGE_SIZE_H_ diff --git a/chromium/pdf/ui/format_page_size_unittest.cc b/chromium/pdf/ui/format_page_size_unittest.cc deleted file mode 100644 index 1bdaff0033f..00000000000 --- a/chromium/pdf/ui/format_page_size_unittest.cc +++ /dev/null @@ -1,163 +0,0 @@ -// Copyright 2021 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/ui/format_page_size.h" - -#include - -#include "base/i18n/number_formatting.h" -#include "base/i18n/rtl.h" -#include "base/optional.h" -#include "base/strings/utf_string_conversions.h" -#include "components/strings/grit/components_strings.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "ui/base/resource/mock_resource_bundle_delegate.h" -#include "ui/base/resource/resource_bundle.h" -#include "ui/gfx/geometry/size.h" - -using ::testing::Invoke; -using ::testing::NiceMock; - -namespace chrome_pdf { - -namespace { - -bool GetPageSizeString(int message_id, base::string16* value) { - std::string utf8; - switch (message_id) { - case IDS_PDF_PROPERTIES_PAGE_SIZE_VALUE_INCH: - utf8 = "$1 × $2 in ($3)"; - break; - case IDS_PDF_PROPERTIES_PAGE_SIZE_VALUE_MM: - utf8 = "$1 × $2 mm ($3)"; - break; - case IDS_PDF_PROPERTIES_PAGE_SIZE_PORTRAIT: - utf8 = "portrait"; - break; - case IDS_PDF_PROPERTIES_PAGE_SIZE_LANDSCAPE: - utf8 = "landscape"; - break; - case IDS_PDF_PROPERTIES_PAGE_SIZE_VARIABLE: - utf8 = "Varies"; - break; - default: - return false; - } - - *value = base::UTF8ToUTF16(utf8); - return true; -} - -class FormatPageSizeTest : public testing::Test { - protected: - void SetUp() override { - // `pdf_unittests` does not have a resource bundle that needs to be restored - // at the end of the test. - ASSERT_FALSE(ui::ResourceBundle::HasSharedInstance()); - - ON_CALL(mock_resource_delegate_, GetLocalizedString) - .WillByDefault(Invoke(GetPageSizeString)); - - const std::string locale(GetLocale()); - ui::ResourceBundle::InitSharedInstanceWithLocale( - locale, &mock_resource_delegate_, - ui::ResourceBundle::DO_NOT_LOAD_COMMON_RESOURCES); - - if (!locale.empty()) { - base::i18n::SetICUDefaultLocale(locale); - base::ResetFormattersForTesting(); - } - } - - void TearDown() override { - ASSERT_TRUE(ui::ResourceBundle::HasSharedInstance()); - ui::ResourceBundle::CleanupSharedInstance(); - base::i18n::SetICUDefaultLocale(default_locale_); - base::ResetFormattersForTesting(); - } - - virtual std::string GetLocale() const { return std::string(); } - - private: - std::string default_locale_{base::i18n::GetConfiguredLocale()}; - NiceMock mock_resource_delegate_; -}; - -std::string FormatPageSizeUtf8(const base::Optional& size_points) { - return base::UTF16ToUTF8(FormatPageSize(size_points)); -} - -} // namespace - -TEST_F(FormatPageSizeTest, NoUniformSize) { - EXPECT_EQ(FormatPageSizeUtf8(base::nullopt), "Varies"); -} - -class FormatPageSizeMillimetersTest : public FormatPageSizeTest { - protected: - std::string GetLocale() const override { return "en_CA"; } -}; - -TEST_F(FormatPageSizeMillimetersTest, EmptySize) { - EXPECT_EQ(FormatPageSizeUtf8(gfx::Size()), "0 × 0 mm (portrait)"); -} - -TEST_F(FormatPageSizeMillimetersTest, Portrait) { - EXPECT_EQ(FormatPageSizeUtf8(gfx::Size(100, 200)), "35 × 71 mm (portrait)"); -} - -TEST_F(FormatPageSizeMillimetersTest, Landscape) { - EXPECT_EQ(FormatPageSizeUtf8(gfx::Size(200, 100)), "71 × 35 mm (landscape)"); -} - -TEST_F(FormatPageSizeMillimetersTest, Square) { - EXPECT_EQ(FormatPageSizeUtf8(gfx::Size(100, 100)), "35 × 35 mm (portrait)"); -} - -TEST_F(FormatPageSizeMillimetersTest, Large) { - EXPECT_EQ(FormatPageSizeUtf8(gfx::Size(72000, 72000)), - "25,400 × 25,400 mm (portrait)"); -} - -class FormatPageSizeMillimetersPeriodSeparatorTest : public FormatPageSizeTest { - protected: - std::string GetLocale() const override { return "de_DE"; } -}; - -TEST_F(FormatPageSizeMillimetersPeriodSeparatorTest, Large) { - EXPECT_EQ(FormatPageSizeUtf8(gfx::Size(72000, 72000)), - "25.400 × 25.400 mm (portrait)"); -} - -class FormatPageSizeInchesTest : public FormatPageSizeTest { - protected: - std::string GetLocale() const override { return "en_US"; } -}; - -TEST_F(FormatPageSizeInchesTest, EmptySize) { - EXPECT_EQ(FormatPageSizeUtf8(gfx::Size()), "0.00 × 0.00 in (portrait)"); -} - -TEST_F(FormatPageSizeInchesTest, Portrait) { - EXPECT_EQ(FormatPageSizeUtf8(gfx::Size(100, 200)), - "1.39 × 2.78 in (portrait)"); -} - -TEST_F(FormatPageSizeInchesTest, Landscape) { - EXPECT_EQ(FormatPageSizeUtf8(gfx::Size(200, 100)), - "2.78 × 1.39 in (landscape)"); -} - -TEST_F(FormatPageSizeInchesTest, Square) { - EXPECT_EQ(FormatPageSizeUtf8(gfx::Size(100, 100)), - "1.39 × 1.39 in (portrait)"); -} - -TEST_F(FormatPageSizeInchesTest, Large) { - EXPECT_EQ(FormatPageSizeUtf8(gfx::Size(72000, 72000)), - "1,000.00 × 1,000.00 in (portrait)"); -} - -} // namespace chrome_pdf diff --git a/chromium/pdf/ui/thumbnail.cc b/chromium/pdf/ui/thumbnail.cc new file mode 100644 index 00000000000..11d82d527c7 --- /dev/null +++ b/chromium/pdf/ui/thumbnail.cc @@ -0,0 +1,125 @@ +// Copyright 2020 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/ui/thumbnail.h" + +#include +#include + +#include "base/check.h" +#include "base/check_op.h" +#include "base/numerics/ranges.h" +#include "base/numerics/safe_math.h" +#include "third_party/skia/include/core/SkBitmap.h" +#include "third_party/skia/include/core/SkImageInfo.h" +#include "ui/gfx/geometry/size.h" + +namespace chrome_pdf { + +namespace { + +constexpr float kMinDevicePixelRatio = 0.25; +constexpr float kMaxDevicePixelRatio = 2; + +constexpr int kImageColorChannels = 4; + +// TODO(crbug.com/702993): Reevaluate the thumbnail size cap when the PDF +// component migrates off of PPAPI. +// The maximum thumbnail area is essentially arbitrary, but the value was chosen +// considering the fact that when sending array buffers through PPAPI, if the +// size of the data is over 256KiB, it gets sent using shared memory instead of +// IPC. Thumbnail sizes are capped at 255KiB to avoid the 256KiB threshold for +// images and their metadata, such as size. +constexpr int kMaxThumbnailPixels = 255 * 1024 / kImageColorChannels; + +// Maximum CSS dimensions are set to match UX specifications. +// These constants should be kept in sync with `PORTRAIT_WIDTH` and +// `LANDSCAPE_WIDTH` in +// chrome/browser/resources/pdf/elements/viewer-thumbnail.js. +constexpr int kMaxWidthPortraitPx = 108; +constexpr int kMaxWidthLandscapePx = 140; + +// PDF page size limits in default user space units, as defined by PDF 1.7 Annex +// C.2, "Architectural limits". +constexpr int kPdfPageMinDimension = 3; +constexpr int kPdfPageMaxDimension = 14400; +constexpr int kPdfMaxAspectRatio = kPdfPageMaxDimension / kPdfPageMinDimension; + +// Limit the proportions within PDF limits to handle pathological PDF pages. +gfx::Size LimitAspectRatio(gfx::Size page_size) { + // Bump up any lengths of 0 to 1. + page_size.SetToMax(gfx::Size(1, 1)); + + if (page_size.height() / page_size.width() > kPdfMaxAspectRatio) + return gfx::Size(kPdfPageMinDimension, kPdfPageMaxDimension); + if (page_size.width() / page_size.height() > kPdfMaxAspectRatio) + return gfx::Size(kPdfPageMaxDimension, kPdfPageMinDimension); + + return page_size; +} + +// Calculate the size of a thumbnail image in device pixels using |page_size| in +// any units and |device_pixel_ratio|. +gfx::Size CalculateBestFitSize(const gfx::Size& page_size, + float device_pixel_ratio) { + gfx::Size safe_page_size = LimitAspectRatio(page_size); + + // Return the larger of the unrotated and rotated sizes to over-sample the PDF + // page so that the thumbnail looks good in different orientations. + float scale_portrait = + static_cast(kMaxWidthPortraitPx) / + std::min(safe_page_size.width(), safe_page_size.height()); + float scale_landscape = + static_cast(kMaxWidthLandscapePx) / + std::max(safe_page_size.width(), safe_page_size.height()); + float scale = std::max(scale_portrait, scale_landscape) * device_pixel_ratio; + + // Using gfx::ScaleToFlooredSize() is fine because `scale` will not yield an + // empty size unless `device_pixel_ratio` is very small (close to 0). + // However, `device_pixel_ratio` support is limited to between 0.25 and 2. + gfx::Size scaled_size = gfx::ScaleToFlooredSize(safe_page_size, scale); + if (scaled_size.GetCheckedArea().ValueOrDefault(kMaxThumbnailPixels + 1) > + kMaxThumbnailPixels) { + // Recalculate `scale` to accommodate pixel size limit such that: + // (scale * safe_page_size.width()) * (scale * safe_page_size.height()) == + // kMaxThumbnailPixels; + scale = std::sqrt(static_cast(kMaxThumbnailPixels) / + safe_page_size.width() / safe_page_size.height()); + return gfx::ScaleToFlooredSize(safe_page_size, scale); + } + + return scaled_size; +} + +} // namespace + +Thumbnail::Thumbnail() = default; + +Thumbnail::Thumbnail(const gfx::Size& page_size, float device_pixel_ratio) { + DCHECK_GE(device_pixel_ratio, kMinDevicePixelRatio); + DCHECK_LE(device_pixel_ratio, kMaxDevicePixelRatio); + device_pixel_ratio_ = base::ClampToRange( + device_pixel_ratio, kMinDevicePixelRatio, kMaxDevicePixelRatio); + + const gfx::Size thumbnail_size_device_pixels = + CalculateBestFitSize(page_size, device_pixel_ratio_); + + // Note that can only hold data in RGBA format. It is the + // responsibility of the thumbnail's renderer to fill `bitmap_` with RGBA + // data. + const SkImageInfo info = + SkImageInfo::Make(thumbnail_size_device_pixels.width(), + thumbnail_size_device_pixels.height(), + kRGBA_8888_SkColorType, kPremul_SkAlphaType); + bool success = bitmap_.tryAllocPixels(info, info.minRowBytes()); + DCHECK(success); +} + +Thumbnail::Thumbnail(Thumbnail&& other) = default; + +Thumbnail& Thumbnail::operator=(Thumbnail&& other) = default; + +Thumbnail::~Thumbnail() = default; + +} // namespace chrome_pdf diff --git a/chromium/pdf/ui/thumbnail.h b/chromium/pdf/ui/thumbnail.h new file mode 100644 index 00000000000..5b343c7fe7e --- /dev/null +++ b/chromium/pdf/ui/thumbnail.h @@ -0,0 +1,41 @@ +// Copyright 2020 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_UI_THUMBNAIL_H_ +#define PDF_UI_THUMBNAIL_H_ + +#include "third_party/skia/include/core/SkBitmap.h" + +namespace gfx { +class Size; +} // namespace gfx + +namespace chrome_pdf { + +class Thumbnail final { + public: + Thumbnail(); + Thumbnail(const gfx::Size& page_size, float device_pixel_ratio); + Thumbnail(Thumbnail&& other); + Thumbnail& operator=(Thumbnail&& other); + ~Thumbnail(); + + SkBitmap& bitmap() { return bitmap_; } + + float device_pixel_ratio() const { return device_pixel_ratio_; } + + private: + // Raw image data of the thumbnail. + SkBitmap bitmap_; + + // Intended resolution of the thumbnail image. The dimensions of `bitmap_` + // are the dimensions of the thumbnail in CSS pixels multiplied by + // `device_pixel_ratio_`. + // Only values between 0.25 and 2 are supported. + float device_pixel_ratio_ = 1; +}; + +} // namespace chrome_pdf + +#endif // PDF_UI_THUMBNAIL_H_ diff --git a/chromium/pdf/ui/thumbnail_unittest.cc b/chromium/pdf/ui/thumbnail_unittest.cc new file mode 100644 index 00000000000..25f78c890df --- /dev/null +++ b/chromium/pdf/ui/thumbnail_unittest.cc @@ -0,0 +1,83 @@ +// Copyright 2020 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/ui/thumbnail.h" + +#include "testing/gtest/include/gtest/gtest.h" +#include "ui/gfx/geometry/size.h" + +namespace chrome_pdf { + +namespace { + +constexpr float kDeviceToPixelLow = 1; +constexpr float kDeviceToPixelHigh = 2; + +struct BestFitSizeParams { + float device_pixel_ratio; + gfx::Size page_size; + gfx::Size expected_thumbnail_size; +}; + +void TestBestFitSize(const BestFitSizeParams& params) { + Thumbnail thumbnail(params.page_size, params.device_pixel_ratio); + EXPECT_EQ(gfx::Size(thumbnail.bitmap().width(), thumbnail.bitmap().height()), + params.expected_thumbnail_size) + << "Failed for page of size of " << params.page_size.ToString() + << " and device to pixel ratio of " << params.device_pixel_ratio; +} + +TEST(ThumbnailTest, CalculateBestFitSizeNormal) { + static constexpr BestFitSizeParams kBestFitSizeTestParams[] = { + {kDeviceToPixelLow, {612, 792}, {108, 140}}, // ANSI Letter + {kDeviceToPixelLow, {595, 842}, {108, 152}}, // ISO 216 A4 + {kDeviceToPixelLow, {200, 200}, {140, 140}}, // Square + {kDeviceToPixelLow, {1000, 200}, {540, 108}}, // Wide + {kDeviceToPixelLow, {200, 1000}, {108, 540}}, // Tall + {kDeviceToPixelLow, {1500, 50}, {1399, 46}}, // Super wide + {kDeviceToPixelLow, {50, 1500}, {46, 1399}}, // Super tall + {kDeviceToPixelHigh, {612, 792}, {216, 280}}, // ANSI Letter + {kDeviceToPixelHigh, {595, 842}, {214, 303}}, // ISO 216 A4 + {kDeviceToPixelHigh, {200, 200}, {255, 255}}, // Square + {kDeviceToPixelHigh, {1000, 200}, {571, 114}}, // Wide + {kDeviceToPixelHigh, {200, 1000}, {114, 571}}, // Tall + {kDeviceToPixelHigh, {1500, 50}, {1399, 46}}, // Super wide + {kDeviceToPixelHigh, {50, 1500}, {46, 1399}}, // Super tall + }; + + for (const auto& params : kBestFitSizeTestParams) + TestBestFitSize(params); +} + +TEST(ThumbnailTest, CalculateBestFitSizeLargeAspectRatio) { + static constexpr BestFitSizeParams kBestFitSizeTestParams[] = { + {kDeviceToPixelLow, {14400, 3}, {17701, 3}}, // PDF 1.7 widest + {kDeviceToPixelLow, {3, 14400}, {3, 17701}}, // PDF 1.7 tallest + {kDeviceToPixelLow, {0, 0}, {140, 140}}, // Empty + {kDeviceToPixelLow, {9999999, 1}, {17701, 3}}, // Very wide + {kDeviceToPixelLow, {1, 9999999}, {3, 17701}}, // Very tall + {kDeviceToPixelHigh, {14400, 3}, {17701, 3}}, // PDF 1.7 widest + {kDeviceToPixelHigh, {3, 14400}, {3, 17701}}, // PDF 1.7 tallest + {kDeviceToPixelHigh, {0, 0}, {255, 255}}, // Empty + {kDeviceToPixelHigh, {9999999, 1}, {17701, 3}}, // Very wide + {kDeviceToPixelHigh, {1, 9999999}, {3, 17701}}, // Very tall + }; + + for (const auto& params : kBestFitSizeTestParams) + TestBestFitSize(params); +} + +TEST(ThumbnailTest, CalculateBestFitSizeNoOverflow) { + static constexpr BestFitSizeParams kBestFitSizeTestParams[] = { + {kDeviceToPixelLow, {9999999, 9999999}, {140, 140}}, // Very large + {kDeviceToPixelHigh, {9999999, 9999999}, {255, 255}}, // Very large + }; + + for (const auto& params : kBestFitSizeTestParams) + TestBestFitSize(params); +} + +} // namespace + +} // namespace chrome_pdf diff --git a/chromium/pdf/url_loader_wrapper_impl.cc b/chromium/pdf/url_loader_wrapper_impl.cc index 5396b639fc8..d740ac386a5 100644 --- a/chromium/pdf/url_loader_wrapper_impl.cc +++ b/chromium/pdf/url_loader_wrapper_impl.cc @@ -17,6 +17,7 @@ #include "base/callback.h" #include "base/check_op.h" #include "base/containers/span.h" +#include "base/location.h" #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" #include "net/http/http_util.h" -- cgit v1.2.1