summaryrefslogtreecommitdiff
path: root/chromium/pdf
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2020-10-12 14:27:29 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2020-10-13 09:35:20 +0000
commitc30a6232df03e1efbd9f3b226777b07e087a1122 (patch)
treee992f45784689f373bcc38d1b79a239ebe17ee23 /chromium/pdf
parent7b5b123ac58f58ffde0f4f6e488bcd09aa4decd3 (diff)
downloadqtwebengine-chromium-c30a6232df03e1efbd9f3b226777b07e087a1122.tar.gz
BASELINE: Update Chromium to 85.0.4183.14085-based
Change-Id: Iaa42f4680837c57725b1344f108c0196741f6057 Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/pdf')
-rw-r--r--chromium/pdf/BUILD.gn6
-rw-r--r--chromium/pdf/accessibility.cc14
-rw-r--r--chromium/pdf/document_attachment_info.cc16
-rw-r--r--chromium/pdf/document_attachment_info.h36
-rw-r--r--chromium/pdf/document_layout.h2
-rw-r--r--chromium/pdf/out_of_process_instance.cc614
-rw-r--r--chromium/pdf/out_of_process_instance.h26
-rw-r--r--chromium/pdf/pdf_engine.h15
-rw-r--r--chromium/pdf/pdf_features.cc14
-rw-r--r--chromium/pdf/pdf_features.h3
-rw-r--r--chromium/pdf/pdfium/accessibility_unittest.cc9
-rw-r--r--chromium/pdf/pdfium/pdfium_api_string_buffer_adapter.cc35
-rw-r--r--chromium/pdf/pdfium/pdfium_api_string_buffer_adapter.h80
-rw-r--r--chromium/pdf/pdfium/pdfium_assert_matching_enums.cc15
-rw-r--r--chromium/pdf/pdfium/pdfium_engine.cc234
-rw-r--r--chromium/pdf/pdfium/pdfium_engine.h28
-rw-r--r--chromium/pdf/pdfium/pdfium_engine_unittest.cc156
-rw-r--r--chromium/pdf/pdfium/pdfium_form_filler.cc15
-rw-r--r--chromium/pdf/pdfium/pdfium_page.cc180
-rw-r--r--chromium/pdf/pdfium/pdfium_page.h157
-rw-r--r--chromium/pdf/pdfium/pdfium_page_unittest.cc166
-rw-r--r--chromium/pdf/pdfium/pdfium_permissions.cc2
-rw-r--r--chromium/pdf/pdfium/pdfium_print.cc2
-rw-r--r--chromium/pdf/pdfium/pdfium_test_base.cc3
-rw-r--r--chromium/pdf/ppapi_migration/README.md5
-rw-r--r--chromium/pdf/ppapi_migration/geometry_conversions.cc (renamed from chromium/pdf/geometry_conversions.cc)2
-rw-r--r--chromium/pdf/ppapi_migration/geometry_conversions.h (renamed from chromium/pdf/geometry_conversions.h)6
-rw-r--r--chromium/pdf/preview_mode_client.cc3
28 files changed, 1304 insertions, 540 deletions
diff --git a/chromium/pdf/BUILD.gn b/chromium/pdf/BUILD.gn
index 495d0258eb1..c0e96cb5df3 100644
--- a/chromium/pdf/BUILD.gn
+++ b/chromium/pdf/BUILD.gn
@@ -49,6 +49,8 @@ if (enable_pdf) {
"accessibility.cc",
"accessibility.h",
"chunk_stream.h",
+ "document_attachment_info.cc",
+ "document_attachment_info.h",
"document_layout.cc",
"document_layout.h",
"document_loader.h",
@@ -60,8 +62,6 @@ if (enable_pdf) {
"draw_utils/coordinates.h",
"draw_utils/shadow.cc",
"draw_utils/shadow.h",
- "geometry_conversions.cc",
- "geometry_conversions.h",
"out_of_process_instance.cc",
"out_of_process_instance.h",
"page_orientation.cc",
@@ -75,6 +75,8 @@ if (enable_pdf) {
"pdf_ppapi.cc",
"pdf_transform.cc",
"pdf_transform.h",
+ "ppapi_migration/geometry_conversions.cc",
+ "ppapi_migration/geometry_conversions.h",
"preview_mode_client.cc",
"preview_mode_client.h",
"range_set.cc",
diff --git a/chromium/pdf/accessibility.cc b/chromium/pdf/accessibility.cc
index 7cf9b5df260..ed259653f69 100644
--- a/chromium/pdf/accessibility.cc
+++ b/chromium/pdf/accessibility.cc
@@ -123,6 +123,7 @@ void GetAccessibilityHighlightInfo(
highlight_info.index_in_page = i;
highlight_info.bounds = std::move(cur_highlight_info.bounds);
highlight_info.color = cur_highlight_info.color;
+ highlight_info.note_text = std::move(cur_highlight_info.note_text);
if (!GetEnclosingTextRunRangeForCharRange(
text_runs, cur_highlight_info.start_char_index,
@@ -165,6 +166,15 @@ void GetAccessibilityTextFieldInfo(
}
}
+void GetAccessibilityFormFieldInfo(
+ PDFEngine* engine,
+ int32_t page_index,
+ uint32_t text_run_count,
+ pp::PDF::PrivateAccessibilityFormFieldInfo* form_fields) {
+ GetAccessibilityTextFieldInfo(engine, page_index, text_run_count,
+ &form_fields->text_fields);
+}
+
} // namespace
bool GetAccessibilityInfo(
@@ -253,8 +263,8 @@ bool GetAccessibilityInfo(
&page_objects->images);
GetAccessibilityHighlightInfo(engine, page_index, *text_runs,
&page_objects->highlights);
- GetAccessibilityTextFieldInfo(engine, page_index, page_info->text_run_count,
- &page_objects->text_fields);
+ GetAccessibilityFormFieldInfo(engine, page_index, page_info->text_run_count,
+ &page_objects->form_fields);
return true;
}
diff --git a/chromium/pdf/document_attachment_info.cc b/chromium/pdf/document_attachment_info.cc
new file mode 100644
index 00000000000..c516cf6418d
--- /dev/null
+++ b/chromium/pdf/document_attachment_info.cc
@@ -0,0 +1,16 @@
+// 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/document_attachment_info.h"
+
+namespace chrome_pdf {
+
+DocumentAttachmentInfo::DocumentAttachmentInfo() = default;
+
+DocumentAttachmentInfo::DocumentAttachmentInfo(
+ const DocumentAttachmentInfo& other) = default;
+
+DocumentAttachmentInfo::~DocumentAttachmentInfo() = default;
+
+} // namespace chrome_pdf
diff --git a/chromium/pdf/document_attachment_info.h b/chromium/pdf/document_attachment_info.h
new file mode 100644
index 00000000000..9c36e1e0644
--- /dev/null
+++ b/chromium/pdf/document_attachment_info.h
@@ -0,0 +1,36 @@
+// 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_DOCUMENT_ATTACHMENT_INFO_H_
+#define PDF_DOCUMENT_ATTACHMENT_INFO_H_
+
+#include "base/strings/string16.h"
+
+namespace chrome_pdf {
+
+struct DocumentAttachmentInfo {
+ DocumentAttachmentInfo();
+
+ DocumentAttachmentInfo(const DocumentAttachmentInfo& other);
+
+ ~DocumentAttachmentInfo();
+
+ // The attachment's name.
+ base::string16 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;
+
+ // Last modified date of the attachment. It stores the arbitrary string saved
+ // in field "ModDate".
+ base::string16 modified_date;
+};
+
+} // namespace chrome_pdf
+
+#endif // PDF_DOCUMENT_ATTACHMENT_INFO_H_
diff --git a/chromium/pdf/document_layout.h b/chromium/pdf/document_layout.h
index c56cbc6bca7..e1907466314 100644
--- a/chromium/pdf/document_layout.h
+++ b/chromium/pdf/document_layout.h
@@ -8,7 +8,7 @@
#include <cstddef>
#include <vector>
-#include "base/logging.h"
+#include "base/check_op.h"
#include "pdf/draw_utils/coordinates.h"
#include "pdf/page_orientation.h"
#include "ppapi/cpp/rect.h"
diff --git a/chromium/pdf/out_of_process_instance.cc b/chromium/pdf/out_of_process_instance.cc
index 9c44da580b2..8214e9716ce 100644
--- a/chromium/pdf/out_of_process_instance.cc
+++ b/chromium/pdf/out_of_process_instance.cc
@@ -16,6 +16,7 @@
#include "base/feature_list.h"
#include "base/logging.h"
#include "base/metrics/histogram_functions.h"
+#include "base/notreached.h"
#include "base/numerics/ranges.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
@@ -109,7 +110,7 @@ constexpr char kJSPrintType[] = "print";
// Save (Page -> Plugin)
constexpr char kJSSaveType[] = "save";
constexpr char kJSToken[] = "token";
-constexpr char kJSForce[] = "force";
+constexpr char kJSSaveRequestType[] = "saveRequestType";
// Save Data (Plugin -> Page)
constexpr char kJSSaveDataType[] = "saveData";
constexpr char kJSFileName[] = "fileName";
@@ -117,6 +118,8 @@ constexpr char kJSDataToSave[] = "dataToSave";
constexpr char kJSHasUnsavedChanges[] = "hasUnsavedChanges";
// 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";
@@ -161,6 +164,9 @@ constexpr char kJSRotateCounterclockwiseType[] = "rotateCounterclockwise";
// Toggle two-up view (Page -> Plugin)
constexpr char kJSSetTwoUpViewType[] = "setTwoUpView";
constexpr char kJSEnableTwoUpView[] = "enableTwoUpView";
+// Display annotations (Page -> Plugin)
+constexpr char kJSDisplayAnnotationsType[] = "displayAnnotations";
+constexpr char kJSDisplayAnnotations[] = "display";
// Select all text in the document (Page -> Plugin)
constexpr char kJSSelectAllType[] = "selectAll";
// Get the selected text in the document (Page -> Plugin)
@@ -180,10 +186,17 @@ constexpr char kJSNamedDestinationPageNumber[] = "pageNumber";
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";
+
constexpr int kFindResultCooldownMs = 100;
// Do not save forms with over 100 MB. This cap should be kept in sync with and
@@ -449,6 +462,8 @@ OutOfProcessInstance::~OutOfProcessInstance() {
bool OutOfProcessInstance::Init(uint32_t argc,
const char* argn[],
const char* argv[]) {
+ DCHECK(!engine_);
+
pp::Var document_url_var = pp::URLUtil_Dev::Get()->GetDocumentURL(this);
if (!document_url_var.is_string())
return false;
@@ -478,7 +493,8 @@ bool OutOfProcessInstance::Init(uint32_t argc,
text_input_ = std::make_unique<pp::TextInput_Dev>(this);
- bool enable_javascript = false;
+ bool enable_javascript = true;
+ bool has_edits = false;
const char* stream_url = nullptr;
const char* original_url = nullptr;
const char* top_level_url = nullptr;
@@ -499,7 +515,10 @@ bool OutOfProcessInstance::Init(uint32_t argc,
success =
base::StringToInt(argv[i], &top_toolbar_height_in_viewport_coords_);
} else if (strcmp(argn[i], "javascript") == 0) {
- enable_javascript = (strcmp(argv[i], "allow") == 0);
+ if (base::FeatureList::IsEnabled(features::kPdfHonorJsContentSettings))
+ enable_javascript = (strcmp(argv[i], "allow") == 0);
+ } else if (strcmp(argn[i], "has-edits") == 0) {
+ has_edits = true;
}
if (!success)
return false;
@@ -511,10 +530,7 @@ bool OutOfProcessInstance::Init(uint32_t argc,
if (!stream_url)
stream_url = original_url;
- if (!engine_) {
- // TODO(tsepez): fix lifetime issue, conditionalize javascript.
- engine_ = PDFEngine::Create(this, true);
- }
+ engine_ = PDFEngine::Create(this, enable_javascript);
// If we're in print preview mode we don't need to load the document yet.
// A |kJSResetPrintPreviewModeType| message will be sent to the plugin letting
@@ -525,6 +541,7 @@ bool OutOfProcessInstance::Init(uint32_t argc,
LoadUrl(stream_url, /*is_print_preview=*/false);
url_ = original_url;
+ edit_mode_ = has_edits;
pp::PDF::SetCrashData(GetPluginInstance(), original_url, top_level_url);
return engine_->New(original_url, headers);
}
@@ -539,259 +556,35 @@ void OutOfProcessInstance::HandleMessage(const pp::Var& message) {
std::string type = dict.Get(kType).AsString();
if (type == kJSViewportType) {
- pp::Var layout_options_var = dict.Get(kJSLayoutOptions);
- if (!layout_options_var.is_undefined()) {
- DocumentLayout::Options layout_options;
- layout_options.FromVar(layout_options_var);
- // TODO(crbug.com/1013800): Eliminate need to get document size from here.
- document_size_ = engine_->ApplyDocumentLayout(layout_options);
- OnGeometryChanged(zoom_, device_scale_);
- }
-
- if (!(dict.Get(pp::Var(kJSXOffset)).is_number() &&
- dict.Get(pp::Var(kJSYOffset)).is_number() &&
- dict.Get(pp::Var(kJSZoom)).is_number() &&
- dict.Get(pp::Var(kJSPinchPhase)).is_number())) {
- NOTREACHED();
- return;
- }
- received_viewport_message_ = true;
- stop_scrolling_ = false;
- PinchPhase pinch_phase =
- static_cast<PinchPhase>(dict.Get(pp::Var(kJSPinchPhase)).AsInt());
- double zoom = dict.Get(pp::Var(kJSZoom)).AsDouble();
- double zoom_ratio = zoom / zoom_;
-
- pp::FloatPoint scroll_offset(dict.Get(pp::Var(kJSXOffset)).AsDouble(),
- dict.Get(pp::Var(kJSYOffset)).AsDouble());
-
- if (pinch_phase == PINCH_START) {
- scroll_offset_at_last_raster_ = scroll_offset;
- last_bitmap_smaller_ = false;
- needs_reraster_ = false;
- return;
- }
-
- // When zooming in, we set a layer transform to avoid unneeded rerasters.
- // Also, if we're zooming out and the last time we rerastered was when
- // we were even further zoomed out (i.e. we pinch zoomed in and are now
- // pinch zooming back out in the same gesture), we update the layer
- // transform instead of rerastering.
- if (pinch_phase == PINCH_UPDATE_ZOOM_IN ||
- (pinch_phase == PINCH_UPDATE_ZOOM_OUT && zoom_ratio > 1.0)) {
- if (!(dict.Get(pp::Var(kJSPinchX)).is_number() &&
- dict.Get(pp::Var(kJSPinchY)).is_number() &&
- dict.Get(pp::Var(kJSPinchVectorX)).is_number() &&
- dict.Get(pp::Var(kJSPinchVectorY)).is_number())) {
- NOTREACHED();
- return;
- }
-
- pp::Point pinch_center(dict.Get(pp::Var(kJSPinchX)).AsDouble(),
- dict.Get(pp::Var(kJSPinchY)).AsDouble());
- // Pinch vector is the panning caused due to change in pinch
- // center between start and end of the gesture.
- pp::Point pinch_vector =
- pp::Point(dict.Get(kJSPinchVectorX).AsDouble() * zoom_ratio,
- dict.Get(kJSPinchVectorY).AsDouble() * zoom_ratio);
- pp::Point scroll_delta;
- // If the rendered document doesn't fill the display area we will
- // use |paint_offset| to anchor the paint vertically into the same place.
- // We use the scroll bars instead of the pinch vector to get the actual
- // position on screen of the paint.
- pp::Point paint_offset;
-
- if (plugin_size_.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 = pp::Point(0, (1 - zoom_ratio) * pinch_center.y());
- scroll_delta =
- pp::Point(0, (scroll_offset.y() -
- scroll_offset_at_last_raster_.y() * zoom_ratio));
-
- pinch_vector = pp::Point();
- last_bitmap_smaller_ = true;
- } else if (last_bitmap_smaller_) {
- pinch_center = pp::Point((plugin_size_.width() / device_scale_) / 2,
- (plugin_size_.height() / device_scale_) / 2);
- const double zoom_when_doc_covers_plugin_width =
- zoom_ * plugin_size_.width() / GetDocumentPixelWidth();
- paint_offset = pp::Point(
- (1 - zoom / zoom_when_doc_covers_plugin_width) * pinch_center.x(),
- (1 - zoom_ratio) * pinch_center.y());
- pinch_vector = pp::Point();
- scroll_delta =
- pp::Point((scroll_offset.x() -
- scroll_offset_at_last_raster_.x() * zoom_ratio),
- (scroll_offset.y() -
- scroll_offset_at_last_raster_.y() * zoom_ratio));
- }
-
- paint_manager_.SetTransform(zoom_ratio, pinch_center,
- pinch_vector + paint_offset + scroll_delta,
- true);
- needs_reraster_ = false;
- return;
- }
-
- if (pinch_phase == PINCH_UPDATE_ZOOM_OUT || pinch_phase == PINCH_END) {
- // We reraster on pinch zoom out in order to solve the invalid regions
- // that appear after zooming out.
- // On pinch end the scale is again 1.f and we request a reraster
- // in the new position.
- paint_manager_.ClearTransform();
- last_bitmap_smaller_ = false;
- needs_reraster_ = true;
-
- // If we're rerastering due to zooming out, we need to update
- // |scroll_offset_at_last_raster_|, in case the user continues the
- // gesture by zooming in.
- scroll_offset_at_last_raster_ = scroll_offset;
- }
-
- // Bound the input parameters.
- zoom = std::max(kMinZoom, zoom);
- DCHECK(dict.Get(pp::Var(kJSUserInitiated)).is_bool());
-
- SetZoom(zoom);
- scroll_offset = BoundScrollOffsetToDocument(scroll_offset);
- engine_->ScrolledToXPosition(scroll_offset.x() * device_scale_);
- engine_->ScrolledToYPosition(scroll_offset.y() * device_scale_);
+ HandleViewportMessage(dict);
} else if (type == kJSGetPasswordCompleteType) {
- if (!dict.Get(pp::Var(kJSPassword)).is_string()) {
- NOTREACHED();
- return;
- }
- if (password_callback_) {
- pp::CompletionCallbackWithOutput<pp::Var> callback = *password_callback_;
- password_callback_.reset();
- *callback.output() = dict.Get(pp::Var(kJSPassword)).pp_var();
- callback.Run(PP_OK);
- } else {
- NOTREACHED();
- }
+ HandleGetPasswordCompleteMessage(dict);
} else if (type == kJSPrintType) {
Print();
} else if (type == kJSSaveType) {
- if (!(dict.Get(pp::Var(kJSToken)).is_string() &&
- dict.Get(pp::Var(kJSForce)).is_bool())) {
- NOTREACHED();
- return;
- }
- const bool force = dict.Get(pp::Var(kJSForce)).AsBool();
- if (force) {
- // |force| being true means the user has entered annotation mode. In which
- // case, assume the user will make edits and prefer saving using the
- // plugin data.
- pp::PDF::SetPluginCanSave(this, true);
- SaveToBuffer(dict.Get(pp::Var(kJSToken)).AsString());
- } else {
- SaveToFile(dict.Get(pp::Var(kJSToken)).AsString());
- }
+ HandlePrintMessage(dict);
} else if (type == kJSRotateClockwiseType) {
RotateClockwise();
} else if (type == kJSRotateCounterclockwiseType) {
RotateCounterclockwise();
} else if (type == kJSSetTwoUpViewType) {
- SetTwoUpView(dict.Get(pp::Var(kJSEnableTwoUpView)).AsBool());
+ HandleSetTwoUpViewMessage(dict);
+ } else if (type == kJSDisplayAnnotationsType) {
+ HandleDisplayAnnotations(dict);
} else if (type == kJSSelectAllType) {
engine_->SelectAll();
} else if (type == kJSBackgroundColorChangedType) {
- if (!dict.Get(pp::Var(kJSBackgroundColor)).is_string()) {
- NOTREACHED();
- return;
- }
- base::HexStringToUInt(dict.Get(pp::Var(kJSBackgroundColor)).AsString(),
- &background_color_);
+ HandleBackgroundColorChangedMessage(dict);
} else if (type == kJSResetPrintPreviewModeType) {
- if (!(dict.Get(pp::Var(kJSPrintPreviewUrl)).is_string() &&
- dict.Get(pp::Var(kJSPrintPreviewGrayscale)).is_bool() &&
- dict.Get(pp::Var(kJSPrintPreviewPageCount)).is_int())) {
- NOTREACHED();
- return;
- }
-
- // For security reasons, crash if the URL that is trying to be loaded here
- // isn't a print preview one.
- std::string url = dict.Get(pp::Var(kJSPrintPreviewUrl)).AsString();
- CHECK(IsPrintPreview());
- CHECK(IsPrintPreviewUrl(url));
-
- int print_preview_page_count =
- dict.Get(pp::Var(kJSPrintPreviewPageCount)).AsInt();
- if (print_preview_page_count < 0) {
- NOTREACHED();
- return;
- }
-
- // The page count is zero if the print preview source is a PDF. In which
- // case, the page index for |url| should be at |kCompletePDFIndex|.
- // When the page count is not zero, then the source is not PDF. In which
- // case, the page index for |url| should be non-negative.
- bool is_previewing_pdf = IsPreviewingPDF(print_preview_page_count);
- int page_index = ExtractPrintPreviewPageIndex(url);
- if (is_previewing_pdf) {
- if (page_index != kCompletePDFIndex) {
- NOTREACHED();
- return;
- }
- } else {
- if (page_index < 0) {
- NOTREACHED();
- return;
- }
- }
-
- print_preview_page_count_ = print_preview_page_count;
- print_preview_loaded_page_count_ = 0;
- url_ = url;
- preview_pages_info_ = base::queue<PreviewPageInfo>();
- preview_document_load_state_ = LOAD_STATE_COMPLETE;
- document_load_state_ = LOAD_STATE_LOADING;
- LoadUrl(url_, /*is_print_preview=*/false);
- preview_engine_.reset();
- engine_ = PDFEngine::Create(this, false);
- engine_->SetGrayscale(dict.Get(pp::Var(kJSPrintPreviewGrayscale)).AsBool());
- engine_->New(url_.c_str(), nullptr /* empty header */);
-
- paint_manager_.InvalidateRect(pp::Rect(pp::Point(), plugin_size_));
+ HandleResetPrintPreviewModeMessage(dict);
} else if (type == kJSLoadPreviewPageType) {
- if (!(dict.Get(pp::Var(kJSPreviewPageUrl)).is_string() &&
- dict.Get(pp::Var(kJSPreviewPageIndex)).is_int())) {
- NOTREACHED();
- return;
- }
-
- std::string url = dict.Get(pp::Var(kJSPreviewPageUrl)).AsString();
- // For security reasons we crash if the URL that is trying to be loaded here
- // isn't a print preview one.
- CHECK(IsPrintPreview());
- CHECK(IsPrintPreviewUrl(url));
- ProcessPreviewPageInfo(url, dict.Get(pp::Var(kJSPreviewPageIndex)).AsInt());
+ HandleLoadPreviewPageMessage(dict);
} else if (type == kJSStopScrollingType) {
stop_scrolling_ = true;
} else if (type == kJSGetSelectedTextType) {
- std::string selected_text = engine_->GetSelectedText();
- // Always return unix newlines to JS.
- base::ReplaceChars(selected_text, "\r", std::string(), &selected_text);
- pp::VarDictionary reply;
- reply.Set(pp::Var(kType), pp::Var(kJSGetSelectedTextReplyType));
- reply.Set(pp::Var(kJSSelectedText), selected_text);
- PostMessage(reply);
+ HandleGetSelectedTextMessage();
} else if (type == kJSGetNamedDestinationType) {
- if (!dict.Get(pp::Var(kJSGetNamedDestination)).is_string()) {
- NOTREACHED();
- return;
- }
- base::Optional<PDFEngine::NamedDestination> named_destination =
- engine_->GetNamedDestination(
- dict.Get(pp::Var(kJSGetNamedDestination)).AsString());
- pp::VarDictionary reply;
- reply.Set(pp::Var(kType), pp::Var(kJSGetNamedDestinationReplyType));
- reply.Set(
- pp::Var(kJSNamedDestinationPageNumber),
- named_destination ? static_cast<int>(named_destination->page) : -1);
- PostMessage(reply);
+ HandleGetNamedDestinationMessage(dict);
} else {
NOTREACHED();
}
@@ -1444,6 +1237,12 @@ void OutOfProcessInstance::NotifySelectedFindResultChanged(
SelectedFindResultChanged(current_find_index);
}
+void OutOfProcessInstance::NotifyTouchSelectionOccurred() {
+ pp::VarDictionary message;
+ message.Set(kType, kJSTouchSelectionOccurredType);
+ PostMessage(message);
+}
+
void OutOfProcessInstance::GetDocumentPassword(
pp::CompletionCallbackWithOutput<pp::Var> callback) {
if (password_callback_) {
@@ -1458,7 +1257,7 @@ void OutOfProcessInstance::GetDocumentPassword(
PostMessage(message);
}
-bool OutOfProcessInstance::ShouldSaveEdits() const {
+bool OutOfProcessInstance::CanSaveEdits() const {
return edit_mode_ &&
base::FeatureList::IsEnabled(features::kSaveEditedPDFForm);
}
@@ -1476,7 +1275,7 @@ void OutOfProcessInstance::SaveToBuffer(const std::string& token) {
edit_mode_ && !base::FeatureList::IsEnabled(features::kSaveEditedPDFForm);
message.Set(kJSHasUnsavedChanges, pp::Var(has_unsaved_changes));
- if (ShouldSaveEdits()) {
+ if (CanSaveEdits()) {
std::vector<uint8_t> data = engine_->GetSaveData();
if (IsSaveDataSizeValid(data.size())) {
pp::VarArrayBuffer buffer(data.size());
@@ -1485,7 +1284,7 @@ void OutOfProcessInstance::SaveToBuffer(const std::string& token) {
message.Set(kJSDataToSave, buffer);
}
} else {
- DCHECK(base::FeatureList::IsEnabled(features::kPDFAnnotations));
+#if defined(OS_CHROMEOS)
uint32_t length = engine_->GetLoadedByteSize();
if (IsSaveDataSizeValid(length)) {
pp::VarArrayBuffer buffer(length);
@@ -1493,20 +1292,18 @@ void OutOfProcessInstance::SaveToBuffer(const std::string& token) {
message.Set(kJSDataToSave, buffer);
}
}
+#else
+ NOTREACHED();
+#endif
}
PostMessage(message);
}
void OutOfProcessInstance::SaveToFile(const std::string& token) {
- if (!ShouldSaveEdits()) {
- engine_->KillFormFocus();
- ConsumeSaveToken(token);
- pp::PDF::SaveAs(this);
- return;
- }
-
- SaveToBuffer(token);
+ engine_->KillFormFocus();
+ ConsumeSaveToken(token);
+ pp::PDF::SaveAs(this);
}
void OutOfProcessInstance::ConsumeSaveToken(const std::string& token) {
@@ -1702,22 +1499,299 @@ void OutOfProcessInstance::RotateCounterclockwise() {
engine_->RotateCounterclockwise();
}
-void OutOfProcessInstance::SetTwoUpView(bool enable_two_up_view) {
- DCHECK(base::FeatureList::IsEnabled(features::kPDFTwoUpView));
- engine_->SetTwoUpView(enable_two_up_view);
-}
-
// 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), std::string() /* content_disposition */,
- std::string() /* referrer_charset */, std::string() /* suggested_name */,
- std::string() /* mime_type */, std::string() /* default_name */);
+ 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::HandleBackgroundColorChangedMessage(
+ const pp::VarDictionary& dict) {
+ if (!dict.Get(pp::Var(kJSBackgroundColor)).is_string()) {
+ NOTREACHED();
+ return;
+ }
+ base::HexStringToUInt(dict.Get(pp::Var(kJSBackgroundColor)).AsString(),
+ &background_color_);
+}
+
+void OutOfProcessInstance::HandleDisplayAnnotations(
+ const pp::VarDictionary& dict) {
+ if (!dict.Get(pp::Var(kJSDisplayAnnotations)).is_bool()) {
+ NOTREACHED();
+ return;
+ }
+
+ engine_->DisplayAnnotations(
+ dict.Get(pp::Var(kJSDisplayAnnotations)).AsBool());
+}
+
+void OutOfProcessInstance::HandleGetNamedDestinationMessage(
+ const pp::VarDictionary& dict) {
+ if (!dict.Get(pp::Var(kJSGetNamedDestination)).is_string()) {
+ NOTREACHED();
+ return;
+ }
+ base::Optional<PDFEngine::NamedDestination> named_destination =
+ engine_->GetNamedDestination(
+ dict.Get(pp::Var(kJSGetNamedDestination)).AsString());
+ pp::VarDictionary reply;
+ reply.Set(pp::Var(kType), pp::Var(kJSGetNamedDestinationReplyType));
+ reply.Set(pp::Var(kJSNamedDestinationPageNumber),
+ named_destination ? static_cast<int>(named_destination->page) : -1);
+ PostMessage(reply);
+}
+
+void OutOfProcessInstance::HandleGetPasswordCompleteMessage(
+ const pp::VarDictionary& dict) {
+ if (!dict.Get(pp::Var(kJSPassword)).is_string() || !password_callback_) {
+ NOTREACHED();
+ return;
+ }
+
+ pp::CompletionCallbackWithOutput<pp::Var> callback = *password_callback_;
+ password_callback_.reset();
+ *callback.output() = dict.Get(pp::Var(kJSPassword)).pp_var();
+ callback.Run(PP_OK);
+}
+
+void OutOfProcessInstance::HandleGetSelectedTextMessage() {
+ std::string selected_text = engine_->GetSelectedText();
+ // Always return unix newlines to JS.
+ base::ReplaceChars(selected_text, "\r", std::string(), &selected_text);
+ pp::VarDictionary reply;
+ reply.Set(pp::Var(kType), pp::Var(kJSGetSelectedTextReplyType));
+ reply.Set(pp::Var(kJSSelectedText), selected_text);
+ PostMessage(reply);
+}
+
+void OutOfProcessInstance::HandleLoadPreviewPageMessage(
+ const pp::VarDictionary& dict) {
+ if (!(dict.Get(pp::Var(kJSPreviewPageUrl)).is_string() &&
+ dict.Get(pp::Var(kJSPreviewPageIndex)).is_int())) {
+ NOTREACHED();
+ return;
+ }
+
+ std::string url = dict.Get(pp::Var(kJSPreviewPageUrl)).AsString();
+ // For security reasons we crash if the URL that is trying to be loaded here
+ // isn't a print preview one.
+ CHECK(IsPrintPreview());
+ CHECK(IsPrintPreviewUrl(url));
+ ProcessPreviewPageInfo(url, dict.Get(pp::Var(kJSPreviewPageIndex)).AsInt());
+}
+
+void OutOfProcessInstance::HandlePrintMessage(const pp::VarDictionary& dict) {
+ if (!(dict.Get(pp::Var(kJSToken)).is_string() &&
+ dict.Get(pp::Var(kJSSaveRequestType)).is_int())) {
+ NOTREACHED();
+ return;
+ }
+ const SaveRequestType request_type = static_cast<SaveRequestType>(
+ dict.Get(pp::Var(kJSSaveRequestType)).AsInt());
+ switch (request_type) {
+ case SaveRequestType::kAnnotation:
+ // In annotation mode, assume the user will make edits and prefer saving
+ // using the plugin data.
+ pp::PDF::SetPluginCanSave(this, true);
+ SaveToBuffer(dict.Get(pp::Var(kJSToken)).AsString());
+ break;
+ case SaveRequestType::kOriginal:
+ pp::PDF::SetPluginCanSave(this, false);
+ SaveToFile(dict.Get(pp::Var(kJSToken)).AsString());
+ pp::PDF::SetPluginCanSave(this, CanSaveEdits());
+ break;
+ case SaveRequestType::kEdited:
+ SaveToBuffer(dict.Get(pp::Var(kJSToken)).AsString());
+ break;
+ }
+}
+
+void OutOfProcessInstance::HandleResetPrintPreviewModeMessage(
+ const pp::VarDictionary& dict) {
+ if (!(dict.Get(pp::Var(kJSPrintPreviewUrl)).is_string() &&
+ dict.Get(pp::Var(kJSPrintPreviewGrayscale)).is_bool() &&
+ dict.Get(pp::Var(kJSPrintPreviewPageCount)).is_int())) {
+ NOTREACHED();
+ return;
+ }
+
+ // For security reasons, crash if the URL that is trying to be loaded here
+ // isn't a print preview one.
+ std::string url = dict.Get(pp::Var(kJSPrintPreviewUrl)).AsString();
+ CHECK(IsPrintPreview());
+ CHECK(IsPrintPreviewUrl(url));
+
+ int print_preview_page_count =
+ dict.Get(pp::Var(kJSPrintPreviewPageCount)).AsInt();
+ if (print_preview_page_count < 0) {
+ NOTREACHED();
+ return;
+ }
+
+ // The page count is zero if the print preview source is a PDF. In which
+ // case, the page index for |url| should be at |kCompletePDFIndex|.
+ // When the page count is not zero, then the source is not PDF. In which
+ // case, the page index for |url| should be non-negative.
+ bool is_previewing_pdf = IsPreviewingPDF(print_preview_page_count);
+ int page_index = ExtractPrintPreviewPageIndex(url);
+ if ((is_previewing_pdf && page_index != kCompletePDFIndex) ||
+ (!is_previewing_pdf && page_index < 0)) {
+ NOTREACHED();
+ return;
+ }
+
+ print_preview_page_count_ = print_preview_page_count;
+ print_preview_loaded_page_count_ = 0;
+ url_ = url;
+ preview_pages_info_ = base::queue<PreviewPageInfo>();
+ preview_document_load_state_ = LOAD_STATE_COMPLETE;
+ document_load_state_ = LOAD_STATE_LOADING;
+ LoadUrl(url_, /*is_print_preview=*/false);
+ preview_engine_.reset();
+ engine_ = PDFEngine::Create(this, false);
+ engine_->SetGrayscale(dict.Get(pp::Var(kJSPrintPreviewGrayscale)).AsBool());
+ engine_->New(url_.c_str(), /*headers=*/nullptr);
+
+ paint_manager_.InvalidateRect(pp::Rect(pp::Point(), plugin_size_));
+}
+
+void OutOfProcessInstance::HandleSetTwoUpViewMessage(
+ const pp::VarDictionary& dict) {
+ if (!base::FeatureList::IsEnabled(features::kPDFTwoUpView) ||
+ !dict.Get(pp::Var(kJSEnableTwoUpView)).is_bool()) {
+ NOTREACHED();
+ return;
+ }
+
+ engine_->SetTwoUpView(dict.Get(pp::Var(kJSEnableTwoUpView)).AsBool());
+}
+
+void OutOfProcessInstance::HandleViewportMessage(
+ const pp::VarDictionary& dict) {
+ pp::Var layout_options_var = dict.Get(kJSLayoutOptions);
+ if (!layout_options_var.is_undefined()) {
+ DocumentLayout::Options layout_options;
+ layout_options.FromVar(layout_options_var);
+ // TODO(crbug.com/1013800): Eliminate need to get document size from here.
+ document_size_ = engine_->ApplyDocumentLayout(layout_options);
+ OnGeometryChanged(zoom_, device_scale_);
+ }
+
+ if (!(dict.Get(pp::Var(kJSXOffset)).is_number() &&
+ dict.Get(pp::Var(kJSYOffset)).is_number() &&
+ dict.Get(pp::Var(kJSZoom)).is_number() &&
+ dict.Get(pp::Var(kJSPinchPhase)).is_number())) {
+ NOTREACHED();
+ return;
+ }
+ received_viewport_message_ = true;
+ stop_scrolling_ = false;
+ PinchPhase pinch_phase =
+ static_cast<PinchPhase>(dict.Get(pp::Var(kJSPinchPhase)).AsInt());
+ double zoom = dict.Get(pp::Var(kJSZoom)).AsDouble();
+ double zoom_ratio = zoom / zoom_;
+
+ pp::FloatPoint scroll_offset(dict.Get(pp::Var(kJSXOffset)).AsDouble(),
+ dict.Get(pp::Var(kJSYOffset)).AsDouble());
+
+ if (pinch_phase == PINCH_START) {
+ scroll_offset_at_last_raster_ = scroll_offset;
+ last_bitmap_smaller_ = false;
+ needs_reraster_ = false;
+ return;
+ }
+
+ // When zooming in, we set a layer transform to avoid unneeded rerasters.
+ // Also, if we're zooming out and the last time we rerastered was when
+ // we were even further zoomed out (i.e. we pinch zoomed in and are now
+ // pinch zooming back out in the same gesture), we update the layer
+ // transform instead of rerastering.
+ if (pinch_phase == PINCH_UPDATE_ZOOM_IN ||
+ (pinch_phase == PINCH_UPDATE_ZOOM_OUT && zoom_ratio > 1.0)) {
+ if (!(dict.Get(pp::Var(kJSPinchX)).is_number() &&
+ dict.Get(pp::Var(kJSPinchY)).is_number() &&
+ dict.Get(pp::Var(kJSPinchVectorX)).is_number() &&
+ dict.Get(pp::Var(kJSPinchVectorY)).is_number())) {
+ NOTREACHED();
+ return;
+ }
+
+ pp::Point pinch_center(dict.Get(pp::Var(kJSPinchX)).AsDouble(),
+ dict.Get(pp::Var(kJSPinchY)).AsDouble());
+ // Pinch vector is the panning caused due to change in pinch
+ // center between start and end of the gesture.
+ pp::Point pinch_vector =
+ pp::Point(dict.Get(kJSPinchVectorX).AsDouble() * zoom_ratio,
+ dict.Get(kJSPinchVectorY).AsDouble() * zoom_ratio);
+ pp::Point scroll_delta;
+ // If the rendered document doesn't fill the display area we will
+ // use |paint_offset| to anchor the paint vertically into the same place.
+ // We use the scroll bars instead of the pinch vector to get the actual
+ // position on screen of the paint.
+ pp::Point paint_offset;
+
+ if (plugin_size_.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 = pp::Point(0, (1 - zoom_ratio) * pinch_center.y());
+ scroll_delta = pp::Point(
+ 0,
+ (scroll_offset.y() - scroll_offset_at_last_raster_.y() * zoom_ratio));
+
+ pinch_vector = pp::Point();
+ last_bitmap_smaller_ = true;
+ } else if (last_bitmap_smaller_) {
+ pinch_center = pp::Point((plugin_size_.width() / device_scale_) / 2,
+ (plugin_size_.height() / device_scale_) / 2);
+ const double zoom_when_doc_covers_plugin_width =
+ zoom_ * plugin_size_.width() / GetDocumentPixelWidth();
+ paint_offset = pp::Point(
+ (1 - zoom / zoom_when_doc_covers_plugin_width) * pinch_center.x(),
+ (1 - zoom_ratio) * pinch_center.y());
+ pinch_vector = pp::Point();
+ scroll_delta = pp::Point(
+ (scroll_offset.x() - scroll_offset_at_last_raster_.x() * zoom_ratio),
+ (scroll_offset.y() - scroll_offset_at_last_raster_.y() * zoom_ratio));
+ }
+
+ paint_manager_.SetTransform(zoom_ratio, pinch_center,
+ pinch_vector + paint_offset + scroll_delta,
+ true);
+ needs_reraster_ = false;
+ return;
+ }
+
+ if (pinch_phase == PINCH_UPDATE_ZOOM_OUT || pinch_phase == PINCH_END) {
+ // We reraster on pinch zoom out in order to solve the invalid regions
+ // that appear after zooming out.
+ // On pinch end the scale is again 1.f and we request a reraster
+ // in the new position.
+ paint_manager_.ClearTransform();
+ last_bitmap_smaller_ = false;
+ needs_reraster_ = true;
+
+ // If we're rerastering due to zooming out, we need to update
+ // |scroll_offset_at_last_raster_|, in case the user continues the
+ // gesture by zooming in.
+ scroll_offset_at_last_raster_ = scroll_offset;
+ }
+
+ // Bound the input parameters.
+ zoom = std::max(kMinZoom, zoom);
+ DCHECK(dict.Get(pp::Var(kJSUserInitiated)).is_bool());
+
+ SetZoom(zoom);
+ scroll_offset = BoundScrollOffsetToDocument(scroll_offset);
+ engine_->ScrolledToXPosition(scroll_offset.x() * device_scale_);
+ engine_->ScrolledToYPosition(scroll_offset.y() * device_scale_);
+}
+
void OutOfProcessInstance::PreviewDocumentLoadComplete() {
if (preview_document_load_state_ != LOAD_STATE_LOADING ||
preview_pages_info_.empty()) {
@@ -1917,15 +1991,27 @@ void OutOfProcessInstance::IsSelectingChanged(bool is_selecting) {
PostMessage(message);
}
-void OutOfProcessInstance::IsEditModeChanged(bool is_edit_mode) {
- edit_mode_ = is_edit_mode;
- pp::PDF::SetPluginCanSave(this, ShouldSaveEdits());
+void OutOfProcessInstance::EnteredEditMode() {
+ edit_mode_ = true;
+ pp::PDF::SetPluginCanSave(this, CanSaveEdits());
+ if (CanSaveEdits()) {
+ pp::VarDictionary message;
+ message.Set(kType, kJSSetIsEditingType);
+ PostMessage(message);
+ }
}
float OutOfProcessInstance::GetToolbarHeightInScreenCoords() {
return top_toolbar_height_in_viewport_coords_ * device_scale_;
}
+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::ProcessPreviewPageInfo(const std::string& url,
int dest_page_index) {
DCHECK(IsPrintPreview());
diff --git a/chromium/pdf/out_of_process_instance.h b/chromium/pdf/out_of_process_instance.h
index db8f4b476e4..b39d0dec7b4 100644
--- a/chromium/pdf/out_of_process_instance.h
+++ b/chromium/pdf/out_of_process_instance.h
@@ -111,6 +111,7 @@ class OutOfProcessInstance : public pp::Instance,
void UpdateTickMarks(const std::vector<pp::Rect>& tickmarks) override;
void NotifyNumberOfFindResultsChanged(int total, bool final_result) override;
void NotifySelectedFindResultChanged(int current_find_index) override;
+ void NotifyTouchSelectionOccurred() override;
void GetDocumentPassword(
pp::CompletionCallbackWithOutput<pp::Var> callback) override;
void Beep() override;
@@ -143,8 +144,9 @@ class OutOfProcessInstance : public pp::Instance,
uint32_t GetBackgroundColor() override;
void IsSelectingChanged(bool is_selecting) override;
void SelectionChanged(const pp::Rect& left, const pp::Rect& right) override;
- void IsEditModeChanged(bool is_edit_mode) override;
+ void EnteredEditMode() override;
float GetToolbarHeightInScreenCoords() override;
+ void DocumentFocusChanged(bool document_has_focus) override;
// PreviewModeClient::Client implementation.
void PreviewDocumentLoadComplete() override;
@@ -153,13 +155,24 @@ class OutOfProcessInstance : public pp::Instance,
// Helper functions for implementing PPP_PDF.
void RotateClockwise();
void RotateCounterclockwise();
- void SetTwoUpView(bool enable_two_up_view);
// Creates a file name for saving a PDF file, given the source URL. Exposed
// for testing.
static std::string GetFileNameFromUrl(const std::string& url);
private:
+ // Message handlers.
+ void HandleBackgroundColorChangedMessage(const pp::VarDictionary& dict);
+ void HandleDisplayAnnotations(const pp::VarDictionary& dict);
+ void HandleGetNamedDestinationMessage(const pp::VarDictionary& dict);
+ void HandleGetPasswordCompleteMessage(const pp::VarDictionary& dict);
+ void HandleGetSelectedTextMessage();
+ void HandleLoadPreviewPageMessage(const pp::VarDictionary& dict);
+ void HandlePrintMessage(const pp::VarDictionary& dict);
+ void HandleResetPrintPreviewModeMessage(const pp::VarDictionary& dict);
+ void HandleSetTwoUpViewMessage(const pp::VarDictionary& dict);
+ void HandleViewportMessage(const pp::VarDictionary& dict);
+
void ResetRecentlySentFindUpdate(int32_t);
// Called whenever the plugin geometry changes to update the location of the
@@ -184,7 +197,7 @@ class OutOfProcessInstance : public pp::Instance,
// frame's origin.
pp::URLLoader CreateURLLoaderInternal();
- bool ShouldSaveEdits() const;
+ bool CanSaveEdits() const;
void SaveToFile(const std::string& token);
void SaveToBuffer(const std::string& token);
void ConsumeSaveToken(const std::string& token);
@@ -210,6 +223,13 @@ class OutOfProcessInstance : public pp::Instance,
LOAD_STATE_FAILED,
};
+ // Must match SaveRequestType in chrome/browser/resources/pdf/constants.js.
+ enum class SaveRequestType {
+ kAnnotation = 0,
+ kOriginal = 1,
+ kEdited = 2,
+ };
+
// Set new zoom scale.
void SetZoom(double scale);
diff --git a/chromium/pdf/pdf_engine.h b/chromium/pdf/pdf_engine.h
index 514e82ea49c..0b4babcdf9e 100644
--- a/chromium/pdf/pdf_engine.h
+++ b/chromium/pdf/pdf_engine.h
@@ -56,6 +56,7 @@ class VarDictionary;
namespace chrome_pdf {
+struct DocumentAttachmentInfo;
struct DocumentMetadata;
// Do one time initialization of the SDK.
@@ -176,6 +177,8 @@ class PDFEngine {
// Updates the index of the currently selected search item.
virtual void NotifySelectedFindResultChanged(int current_find_index) {}
+ virtual void NotifyTouchSelectionOccurred() {}
+
// Prompts the user for a password to open this document. The callback is
// called when the password is retrieved.
virtual void GetDocumentPassword(
@@ -258,12 +261,15 @@ class PDFEngine {
virtual void SelectionChanged(const pp::Rect& left, const pp::Rect& right) {
}
- // Sets edit mode state.
- virtual void IsEditModeChanged(bool is_edit_mode) {}
+ // Notifies the client that the PDF has been edited.
+ virtual void EnteredEditMode() {}
// Gets the height of the top toolbar in screen coordinates. This is
// independent of whether it is hidden or not at the moment.
virtual float GetToolbarHeightInScreenCoords() = 0;
+
+ // Notifies the client about focus changes for the document.
+ virtual void DocumentFocusChanged(bool document_has_focus) {}
};
struct AccessibilityLinkInfo {
@@ -283,6 +289,7 @@ class PDFEngine {
int char_count;
pp::FloatRect bounds;
uint32_t color;
+ std::string note_text;
};
struct AccessibilityTextFieldInfo {
@@ -336,6 +343,7 @@ class PDFEngine {
virtual void RotateClockwise() = 0;
virtual void RotateCounterclockwise() = 0;
virtual void SetTwoUpView(bool enable) = 0;
+ virtual void DisplayAnnotations(bool display) = 0;
// Applies the document layout options proposed by a call to
// PDFEngine::Client::ProposeDocumentLayout(), returning the overall size of
@@ -365,6 +373,9 @@ class PDFEngine {
// Checks the permissions associated with this document.
virtual bool HasPermission(DocumentPermission permission) const = 0;
virtual void SelectAll() = 0;
+ // Gets the list of DocumentAttachmentInfo from the document.
+ virtual const std::vector<DocumentAttachmentInfo>&
+ GetDocumentAttachmentInfoList() const = 0;
// Gets metadata about the document.
virtual const DocumentMetadata& GetDocumentMetadata() const = 0;
// Gets the number of pages in the document.
diff --git a/chromium/pdf/pdf_features.cc b/chromium/pdf/pdf_features.cc
index ae908960a06..df8ae4c88ab 100644
--- a/chromium/pdf/pdf_features.cc
+++ b/chromium/pdf/pdf_features.cc
@@ -13,17 +13,15 @@ const base::Feature kAccessiblePDFForm = {"AccessiblePDFForm",
const base::Feature kAccessiblePDFHighlight = {
"AccessiblePDFHighlight", base::FEATURE_ENABLED_BY_DEFAULT};
-const base::Feature kPDFAnnotations = {"PDFAnnotations",
-#if defined(OS_CHROMEOS)
- base::FEATURE_ENABLED_BY_DEFAULT
-#else
- base::FEATURE_DISABLED_BY_DEFAULT
-#endif // defined(OS_CHROMEOS)
-};
+const base::Feature kPdfHonorJsContentSettings = {
+ "PdfHonorJsContentSettings", base::FEATURE_DISABLED_BY_DEFAULT};
const base::Feature kPDFTwoUpView = {"PDFTwoUpView",
base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kPDFViewerUpdate = {"PDFViewerUpdate",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
const base::Feature kSaveEditedPDFForm = {"SaveEditedPDFForm",
#if defined(OS_CHROMEOS)
base::FEATURE_ENABLED_BY_DEFAULT
@@ -33,7 +31,7 @@ const base::Feature kSaveEditedPDFForm = {"SaveEditedPDFForm",
};
const base::Feature kTabAcrossPDFAnnotations = {
- "TabAcrossPDFAnnotations", base::FEATURE_DISABLED_BY_DEFAULT};
+ "TabAcrossPDFAnnotations", base::FEATURE_ENABLED_BY_DEFAULT};
} // namespace features
} // namespace chrome_pdf
diff --git a/chromium/pdf/pdf_features.h b/chromium/pdf/pdf_features.h
index eb698f22b6b..6dca39fa395 100644
--- a/chromium/pdf/pdf_features.h
+++ b/chromium/pdf/pdf_features.h
@@ -15,8 +15,9 @@ namespace features {
extern const base::Feature kAccessiblePDFForm;
extern const base::Feature kAccessiblePDFHighlight;
-extern const base::Feature kPDFAnnotations;
+extern const base::Feature kPdfHonorJsContentSettings;
extern const base::Feature kPDFTwoUpView;
+extern const base::Feature kPDFViewerUpdate;
extern const base::Feature kSaveEditedPDFForm;
extern const base::Feature kTabAcrossPDFAnnotations;
diff --git a/chromium/pdf/pdfium/accessibility_unittest.cc b/chromium/pdf/pdfium/accessibility_unittest.cc
index f23e103ffde..98eb154f5ae 100644
--- a/chromium/pdf/pdfium/accessibility_unittest.cc
+++ b/chromium/pdf/pdfium/accessibility_unittest.cc
@@ -485,7 +485,7 @@ TEST_F(AccessibilityTest, GetAccessibilityHighlightInfo) {
constexpr uint32_t kHighlightNoColor = MakeARGB(0, 0, 0, 0);
static const pp::PDF::PrivateAccessibilityHighlightInfo
kExpectedHighlightInfo[] = {
- {"", 0, 0, 1, {{5, 196}, {49, 26}}, kHighlightDefaultColor},
+ {"Text Note", 0, 0, 1, {{5, 196}, {49, 26}}, kHighlightDefaultColor},
{"", 1, 2, 1, {{110, 196}, {77, 26}}, kHighlightRedColor},
{"", 2, 3, 1, {{192, 196}, {13, 26}}, kHighlightNoColor}};
@@ -520,6 +520,7 @@ TEST_F(AccessibilityTest, GetAccessibilityHighlightInfo) {
EXPECT_EQ(highlight_info.text_run_count,
kExpectedHighlightInfo[i].text_run_count);
EXPECT_EQ(highlight_info.color, kExpectedHighlightInfo[i].color);
+ EXPECT_EQ(highlight_info.note_text, kExpectedHighlightInfo[i].note_text);
}
}
@@ -563,12 +564,12 @@ TEST_F(AccessibilityTest, GetAccessibilityTextFieldInfo) {
CompareRect(kExpectedPageRect, page_info.bounds);
EXPECT_EQ(text_runs.size(), page_info.text_run_count);
EXPECT_EQ(chars.size(), page_info.char_count);
- ASSERT_EQ(page_objects.text_fields.size(),
+ ASSERT_EQ(page_objects.form_fields.text_fields.size(),
base::size(kExpectedTextFieldInfo));
- for (size_t i = 0; i < page_objects.text_fields.size(); ++i) {
+ for (size_t i = 0; i < page_objects.form_fields.text_fields.size(); ++i) {
const pp::PDF::PrivateAccessibilityTextFieldInfo& text_field_info =
- page_objects.text_fields[i];
+ page_objects.form_fields.text_fields[i];
EXPECT_EQ(kExpectedTextFieldInfo[i].name, text_field_info.name);
EXPECT_EQ(kExpectedTextFieldInfo[i].value, text_field_info.value);
EXPECT_EQ(kExpectedTextFieldInfo[i].is_read_only,
diff --git a/chromium/pdf/pdfium/pdfium_api_string_buffer_adapter.cc b/chromium/pdf/pdfium/pdfium_api_string_buffer_adapter.cc
index 382b3a9385c..9e02e34906f 100644
--- a/chromium/pdf/pdfium/pdfium_api_string_buffer_adapter.cc
+++ b/chromium/pdf/pdfium/pdfium_api_string_buffer_adapter.cc
@@ -6,14 +6,13 @@
#include <stddef.h>
-#include <string>
-
#include "base/check_op.h"
-#include "base/strings/string16.h"
#include "base/strings/string_util.h"
namespace chrome_pdf {
+namespace internal {
+
template <class StringType>
PDFiumAPIStringBufferAdapter<StringType>::PDFiumAPIStringBufferAdapter(
StringType* str,
@@ -52,36 +51,30 @@ void PDFiumAPIStringBufferAdapter<StringType>::Close(size_t actual_size) {
}
}
-template <class StringType>
-PDFiumAPIStringBufferSizeInBytesAdapter<StringType>::
- PDFiumAPIStringBufferSizeInBytesAdapter(StringType* str,
+PDFiumAPIStringBufferSizeInBytesAdapter::
+ PDFiumAPIStringBufferSizeInBytesAdapter(base::string16* str,
size_t expected_size,
bool check_expected_size)
- : adapter_(str,
- expected_size / sizeof(typename StringType::value_type),
- check_expected_size) {
- DCHECK(expected_size % sizeof(typename StringType::value_type) == 0);
+ : adapter_(str, expected_size / sizeof(base::char16), check_expected_size) {
+ DCHECK(expected_size % sizeof(base::char16) == 0);
}
-template <class StringType>
-PDFiumAPIStringBufferSizeInBytesAdapter<
- StringType>::~PDFiumAPIStringBufferSizeInBytesAdapter() = default;
+PDFiumAPIStringBufferSizeInBytesAdapter::
+ ~PDFiumAPIStringBufferSizeInBytesAdapter() = default;
-template <class StringType>
-void* PDFiumAPIStringBufferSizeInBytesAdapter<StringType>::GetData() {
+void* PDFiumAPIStringBufferSizeInBytesAdapter::GetData() {
return adapter_.GetData();
}
-template <class StringType>
-void PDFiumAPIStringBufferSizeInBytesAdapter<StringType>::Close(
- size_t actual_size) {
- DCHECK(actual_size % sizeof(typename StringType::value_type) == 0);
- adapter_.Close(actual_size / sizeof(typename StringType::value_type));
+void PDFiumAPIStringBufferSizeInBytesAdapter::Close(size_t actual_size) {
+ DCHECK(actual_size % sizeof(base::char16) == 0);
+ adapter_.Close(actual_size / sizeof(base::char16));
}
// explicit instantiations
template class PDFiumAPIStringBufferAdapter<std::string>;
template class PDFiumAPIStringBufferAdapter<base::string16>;
-template class PDFiumAPIStringBufferSizeInBytesAdapter<base::string16>;
+
+} // namespace internal
} // namespace chrome_pdf
diff --git a/chromium/pdf/pdfium/pdfium_api_string_buffer_adapter.h b/chromium/pdf/pdfium/pdfium_api_string_buffer_adapter.h
index d3a413cd5a7..9c2587a19bf 100644
--- a/chromium/pdf/pdfium/pdfium_api_string_buffer_adapter.h
+++ b/chromium/pdf/pdfium/pdfium_api_string_buffer_adapter.h
@@ -7,16 +7,21 @@
#include <stddef.h>
+#include <string>
+
+#include "base/callback.h"
#include "base/macros.h"
#include "base/numerics/safe_math.h"
+#include "base/strings/string16.h"
namespace chrome_pdf {
+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 plugin likes to pass
-// in std::strings / base::string16s, where one should not count on the internal
+// 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
// string buffers to be null-terminated.
-
template <class StringType>
class PDFiumAPIStringBufferAdapter {
public:
@@ -56,11 +61,11 @@ 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 plugin likes to pass
-// in std::strings / base::string16s, where one should not count on the internal
+// 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
// 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.
-template <class StringType>
+// work in terms of number of bytes instead of the number of characters. Though
+// for std::strings, PDFiumAPIStringBufferAdapter is equivalent.
class PDFiumAPIStringBufferSizeInBytesAdapter {
public:
// |str| is the string to write into.
@@ -69,19 +74,19 @@ 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(StringType* str,
+ PDFiumAPIStringBufferSizeInBytesAdapter(base::string16* 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(StringType::value_type) bytes, so the PDFium
- // API that uses the pointer has space to write a null-terminator.
+ // hold |expected_size_| + sizeof(base::char16) bytes, so the PDFium API that
+ // uses the pointer has space to write a null-terminator.
void* GetData();
- // Resizes |str_| to |actual_size| - sizeof(StringType::value_type) bytes,
- // thereby removing the extra null-terminator. This must be called prior to
- // the adapter's destruction. The pointer returned by GetData() should be
+ // Resizes |str_| to |actual_size| - sizeof(base::char16) 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.
void Close(size_t actual_size);
@@ -91,9 +96,56 @@ class PDFiumAPIStringBufferSizeInBytesAdapter {
}
private:
- PDFiumAPIStringBufferAdapter<StringType> adapter_;
+ PDFiumAPIStringBufferAdapter<base::string16> adapter_;
};
+template <class AdapterType,
+ class StringType,
+ typename BufferType,
+ typename ReturnType>
+StringType CallPDFiumStringBufferApi(
+ base::RepeatingCallback<ReturnType(BufferType*, ReturnType)> api,
+ bool check_expected_size) {
+ StringType str;
+ ReturnType expected_size = api.Run(nullptr, 0);
+ if (expected_size > 0) {
+ AdapterType api_string_adapter(&str, expected_size, check_expected_size);
+ auto* data = reinterpret_cast<BufferType*>(api_string_adapter.GetData());
+ api_string_adapter.Close(api.Run(data, expected_size));
+ }
+ return str;
+}
+
+} // namespace internal
+
+// Helper function to call PDFium APIs where the output buffer is expected to
+// hold UTF-16 data, and the buffer length is specified in bytes.
+template <typename BufferType>
+base::string16 CallPDFiumWideStringBufferApi(
+ base::RepeatingCallback<unsigned long(BufferType*, unsigned long)> api,
+ bool check_expected_size) {
+ using adapter_type = internal::PDFiumAPIStringBufferSizeInBytesAdapter;
+ return internal::CallPDFiumStringBufferApi<adapter_type, base::string16>(
+ api, check_expected_size);
+}
+
+// Helper function to call PDFium APIs where the output buffer is expected to
+// hold ASCII or UTF-8 data, and the buffer length is specified in bytes.
+template <typename BufferType, typename ReturnType>
+std::string CallPDFiumStringBufferApi(
+ base::RepeatingCallback<ReturnType(BufferType*, ReturnType)> api,
+ bool check_expected_size) {
+ using adapter_type = internal::PDFiumAPIStringBufferAdapter<std::string>;
+ return internal::CallPDFiumStringBufferApi<adapter_type, std::string>(
+ api, check_expected_size);
+}
+
+// Expose internal::PDFiumAPIStringBufferAdapter for special cases that cannot
+// use the CallPDFiumStringBuffer* functions above.
+template <class StringType>
+using PDFiumAPIStringBufferAdapter =
+ internal::PDFiumAPIStringBufferAdapter<StringType>;
+
} // namespace chrome_pdf
#endif // PDF_PDFIUM_PDFIUM_API_STRING_BUFFER_ADAPTER_H_
diff --git a/chromium/pdf/pdfium/pdfium_assert_matching_enums.cc b/chromium/pdf/pdfium/pdfium_assert_matching_enums.cc
index a58ecff0daa..fc52f804e9c 100644
--- a/chromium/pdf/pdfium/pdfium_assert_matching_enums.cc
+++ b/chromium/pdf/pdfium/pdfium_assert_matching_enums.cc
@@ -4,10 +4,12 @@
#include "build/build_config.h"
#include "pdf/pdf.h"
+#include "pdf/pdf_engine.h"
#include "ppapi/c/pp_input_event.h"
#include "ppapi/c/private/ppb_pdf.h"
#include "ppapi/c/private/ppp_pdf.h"
#include "third_party/pdfium/public/fpdf_edit.h"
+#include "third_party/pdfium/public/fpdf_formfill.h"
#include "third_party/pdfium/public/fpdf_fwlevent.h"
#include "third_party/pdfium/public/fpdf_sysfontinfo.h"
#include "third_party/pdfium/public/fpdfview.h"
@@ -229,6 +231,19 @@ STATIC_ASSERT_ENUM(PP_TEXTRENDERINGMODE_FILLSTROKECLIP,
FPDF_TEXTRENDERMODE_FILL_STROKE_CLIP);
STATIC_ASSERT_ENUM(PP_TEXTRENDERINGMODE_CLIP, FPDF_TEXTRENDERMODE_CLIP);
+STATIC_ASSERT_ENUM(chrome_pdf::PDFEngine::FormType::kNone, FORMTYPE_NONE);
+STATIC_ASSERT_ENUM(chrome_pdf::PDFEngine::FormType::kAcroForm,
+ FORMTYPE_ACRO_FORM);
+STATIC_ASSERT_ENUM(chrome_pdf::PDFEngine::FormType::kXFAFull,
+ FORMTYPE_XFA_FULL);
+STATIC_ASSERT_ENUM(chrome_pdf::PDFEngine::FormType::kXFAForeground,
+ FORMTYPE_XFA_FOREGROUND);
+STATIC_ASSERT_ENUM(chrome_pdf::PDFEngine::FormType::kCount, FORMTYPE_COUNT);
+
+STATIC_ASSERT_ENUM(PP_PRIVATEBUTTON_PUSHBUTTON, FPDF_FORMFIELD_PUSHBUTTON);
+STATIC_ASSERT_ENUM(PP_PRIVATEBUTTON_CHECKBOX, FPDF_FORMFIELD_CHECKBOX);
+STATIC_ASSERT_ENUM(PP_PRIVATEBUTTON_RADIOBUTTON, FPDF_FORMFIELD_RADIOBUTTON);
+
#if defined(OS_WIN)
STATIC_ASSERT_ENUM(chrome_pdf::kEmf, FPDF_PRINTMODE_EMF);
STATIC_ASSERT_ENUM(chrome_pdf::kTextOnly, FPDF_PRINTMODE_TEXTONLY);
diff --git a/chromium/pdf/pdfium/pdfium_engine.cc b/chromium/pdf/pdfium/pdfium_engine.cc
index 090a8edcbdf..66f988b568b 100644
--- a/chromium/pdf/pdfium/pdfium_engine.cc
+++ b/chromium/pdf/pdfium/pdfium_engine.cc
@@ -28,6 +28,7 @@
#include "gin/array_buffer.h"
#include "gin/public/gin_embedders.h"
#include "gin/public/isolate_holder.h"
+#include "gin/public/v8_platform.h"
#include "pdf/document_loader_impl.h"
#include "pdf/draw_utils/coordinates.h"
#include "pdf/draw_utils/shadow.h"
@@ -68,20 +69,6 @@ using printing::kPixelsPerInch;
namespace chrome_pdf {
-static_assert(static_cast<int>(PDFEngine::FormType::kNone) == FORMTYPE_NONE,
- "None form types must match");
-static_assert(static_cast<int>(PDFEngine::FormType::kAcroForm) ==
- FORMTYPE_ACRO_FORM,
- "AcroForm form types must match");
-static_assert(static_cast<int>(PDFEngine::FormType::kXFAFull) ==
- FORMTYPE_XFA_FULL,
- "XFA full form types must match");
-static_assert(static_cast<int>(PDFEngine::FormType::kXFAForeground) ==
- FORMTYPE_XFA_FOREGROUND,
- "XFA foreground form types must match");
-static_assert(static_cast<int>(PDFEngine::FormType::kCount) == FORMTYPE_COUNT,
- "Form type counts must match");
-
namespace {
constexpr int32_t kHighlightColorR = 153;
@@ -234,8 +221,10 @@ bool IsV8Initialized() {
void SetUpV8() {
const char* recommended = FPDF_GetRecommendedV8Flags();
v8::V8::SetFlagsFromString(recommended, strlen(recommended));
- gin::IsolateHolder::Initialize(gin::IsolateHolder::kNonStrictMode,
- gin::ArrayBufferAllocator::SharedInstance());
+ gin::IsolateHolder::Initialize(
+ gin::IsolateHolder::kNonStrictMode,
+ static_cast<v8::ArrayBuffer::Allocator*>(
+ FPDF_GetArrayBufferAllocatorSharedInstance()));
DCHECK(!g_isolate_holder);
g_isolate_holder = new gin::IsolateHolder(
base::ThreadTaskRunnerHandle::Get(), gin::IsolateHolder::kSingleThread,
@@ -365,18 +354,44 @@ void SetLinkUnderCursor(pp::Instance* instance,
pp::PDF::SetLinkUnderCursor(instance, link_under_cursor.c_str());
}
+base::string16 GetAttachmentAttribute(FPDF_ATTACHMENT attachment,
+ FPDF_BYTESTRING field) {
+ return CallPDFiumWideStringBufferApi(
+ base::BindRepeating(&FPDFAttachment_GetStringValue, attachment, field),
+ /*check_expected_size=*/true);
+}
+
+unsigned long GetAttachmentFileLengthInBytes(FPDF_ATTACHMENT attachment) {
+ unsigned long actual_length_bytes;
+ bool is_attachment_readable = FPDFAttachment_GetFile(
+ attachment, /*buffer=*/nullptr, /*buflen=*/0, &actual_length_bytes);
+ DCHECK(is_attachment_readable);
+ return actual_length_bytes;
+}
+
+base::string16 GetAttachmentName(FPDF_ATTACHMENT attachment) {
+ return CallPDFiumWideStringBufferApi(
+ base::BindRepeating(&FPDFAttachment_GetName, attachment),
+ /*check_expected_size=*/true);
+}
+
} // namespace
void InitializeSDK(bool enable_v8) {
FPDF_LIBRARY_CONFIG config;
- config.version = 2;
+ config.version = 3;
config.m_pUserFontPaths = nullptr;
if (enable_v8) {
SetUpV8();
config.m_pIsolate = v8::Isolate::GetCurrent();
+ // NOTE: static_cast<> prior to assigning to (void*) is safer since it
+ // will manipulate the pointer value should gin::V8Platform someday have
+ // multiple base classes.
+ config.m_pPlatform = static_cast<v8::Platform*>(gin::V8Platform::Get());
} else {
config.m_pIsolate = nullptr;
+ config.m_pPlatform = nullptr;
}
config.m_v8EmbedderSlot = gin::kEmbedderPDFium;
FPDF_InitLibraryWithConfig(&config);
@@ -746,6 +761,8 @@ void PDFiumEngine::FinishLoadingDocument() {
if (need_update)
LoadPageInfo();
+ LoadDocumentAttachmentInfoList();
+
LoadDocumentMetadata();
if (called_do_document_action_)
@@ -948,7 +965,7 @@ void PDFiumEngine::KillFormFocus() {
void PDFiumEngine::UpdateFocus(bool has_focus) {
base::AutoReset<bool> updating_focus_guard(&updating_focus_, true);
if (has_focus) {
- focus_item_type_ = last_focused_item_type_;
+ UpdateFocusItemType(last_focused_item_type_);
if (focus_item_type_ == FocusElementType::kPage &&
PageIndexInBounds(last_focused_page_) &&
last_focused_annot_index_ != -1) {
@@ -962,7 +979,7 @@ void PDFiumEngine::UpdateFocus(bool has_focus) {
} else {
last_focused_item_type_ = focus_item_type_;
if (focus_item_type_ == FocusElementType::kDocument) {
- focus_item_type_ = FocusElementType::kNone;
+ UpdateFocusItemType(FocusElementType::kNone);
} else if (focus_item_type_ == FocusElementType::kPage) {
FPDF_ANNOTATION last_focused_annot = nullptr;
FPDF_BOOL ret = FORM_GetFocusedAnnot(form(), &last_focused_page_,
@@ -991,21 +1008,15 @@ bool PDFiumEngine::ReadLoadedBytes(uint32_t length, void* buffer) {
void PDFiumEngine::SetFormSelectedText(FPDF_FORMHANDLE form_handle,
FPDF_PAGE page) {
- unsigned long form_sel_text_len =
- FORM_GetSelectedText(form_handle, page, nullptr, 0);
+ base::string16 selected_form_text16 = CallPDFiumWideStringBufferApi(
+ base::BindRepeating(&FORM_GetSelectedText, form_handle, page),
+ /*check_expected_size=*/false);
// If form selected text is empty and there was no previous form text
- // selection, exit early because nothing has changed. When |form_sel_text_len|
- // is 2, that represents a wide string with just a NUL-terminator.
- if (form_sel_text_len <= 2 && selected_form_text_.empty())
+ // selection, exit early because nothing has changed.
+ if (selected_form_text16.empty() && selected_form_text_.empty())
return;
- base::string16 selected_form_text16;
- PDFiumAPIStringBufferSizeInBytesAdapter<base::string16> string_adapter(
- &selected_form_text16, form_sel_text_len, false);
- string_adapter.Close(FORM_GetSelectedText(
- form_handle, page, string_adapter.GetData(), form_sel_text_len));
-
// Update previous and current selections, then compare them to check if
// selection has changed. If so, set plugin text selection.
std::string selected_form_text = selected_form_text_;
@@ -1098,6 +1109,9 @@ void PDFiumEngine::OnMultipleClick(int click_count,
selection_.push_back(PDFiumRange(pages_[page_index].get(), start_index,
end_index - start_index));
+
+ if (handling_long_press_)
+ client_->NotifyTouchSelectionOccurred();
}
bool PDFiumEngine::OnLeftMouseDown(const pp::MouseInputEvent& event) {
@@ -1123,7 +1137,7 @@ bool PDFiumEngine::OnLeftMouseDown(const pp::MouseInputEvent& event) {
return true;
if (page_index != -1) {
- focus_item_type_ = FocusElementType::kPage;
+ UpdateFocusItemType(FocusElementType::kPage);
last_focused_page_ = page_index;
double page_x;
double page_y;
@@ -1554,6 +1568,17 @@ bool PDFiumEngine::OnKeyDown(const pp::KeyboardInputEvent& event) {
OnChar(synthesized);
}
+#if !defined(OS_MACOSX)
+ // macOS doesn't have keyboard-triggered context menus.
+ // Scroll focused annotation into view when context menu is invoked through
+ // keyboard <Shift-F10>.
+ if (event.GetKeyCode() == FWL_VKEY_F10 &&
+ (event.GetModifiers() & PP_INPUTEVENT_MODIFIER_SHIFTKEY)) {
+ DCHECK(!rv);
+ ScrollFocusedAnnotationIntoView();
+ }
+#endif
+
return rv;
}
@@ -1574,8 +1599,17 @@ bool PDFiumEngine::OnChar(const pp::KeyboardInputEvent& event) {
return false;
base::string16 str = base::UTF8ToUTF16(event.GetCharacterText().AsString());
- return !!FORM_OnChar(form(), pages_[last_focused_page_]->GetPage(), str[0],
- event.GetModifiers());
+ bool rv = !!FORM_OnChar(form(), pages_[last_focused_page_]->GetPage(), str[0],
+ event.GetModifiers());
+
+ // Scroll editable form text into view on char events. We should not scroll
+ // focused annotation on escape char event since escape char is used to
+ // dismiss focus from form controls.
+ if (rv && editable_form_text_area_ && event.GetKeyCode() != ui::VKEY_ESCAPE) {
+ ScrollFocusedAnnotationIntoView();
+ }
+
+ return rv;
}
void PDFiumEngine::StartFind(const std::string& text, bool case_sensitive) {
@@ -1974,6 +2008,14 @@ void PDFiumEngine::SetTwoUpView(bool enable) {
ProposeNextDocumentLayout();
}
+void PDFiumEngine::DisplayAnnotations(bool display) {
+ if (render_annots_ == display)
+ return;
+
+ render_annots_ = display;
+ InvalidateAllPages();
+}
+
void PDFiumEngine::InvalidateAllPages() {
CancelPaints();
StopFind();
@@ -2124,6 +2166,12 @@ void PDFiumEngine::SelectAll() {
}
}
+const std::vector<DocumentAttachmentInfo>&
+PDFiumEngine::GetDocumentAttachmentInfoList() const {
+ DCHECK(document_loaded_);
+ return doc_attachment_info_list_;
+}
+
const DocumentMetadata& PDFiumEngine::GetDocumentMetadata() const {
DCHECK(document_loaded_);
return doc_metadata_;
@@ -2142,14 +2190,9 @@ pp::VarArray PDFiumEngine::GetBookmarks() {
pp::VarDictionary PDFiumEngine::TraverseBookmarks(FPDF_BOOKMARK bookmark,
unsigned int depth) {
pp::VarDictionary dict;
- base::string16 title;
- unsigned long buffer_size = FPDFBookmark_GetTitle(bookmark, nullptr, 0);
- if (buffer_size > 0) {
- PDFiumAPIStringBufferSizeInBytesAdapter<base::string16> api_string_adapter(
- &title, buffer_size, true);
- api_string_adapter.Close(FPDFBookmark_GetTitle(
- bookmark, api_string_adapter.GetData(), buffer_size));
- }
+ base::string16 title = CallPDFiumWideStringBufferApi(
+ base::BindRepeating(&FPDFBookmark_GetTitle, bookmark),
+ /*check_expected_size=*/true);
dict.Set(pp::Var("title"), pp::Var(base::UTF16ToUTF8(title)));
FPDF_DEST dest = FPDFBookmark_GetDest(doc(), bookmark);
@@ -2173,15 +2216,11 @@ pp::VarDictionary PDFiumEngine::TraverseBookmarks(FPDF_BOOKMARK bookmark,
} else {
// Extract URI for bookmarks linking to an external page.
FPDF_ACTION action = FPDFBookmark_GetAction(bookmark);
- buffer_size = FPDFAction_GetURIPath(doc(), action, nullptr, 0);
- if (buffer_size > 0) {
- std::string uri;
- PDFiumAPIStringBufferAdapter<std::string> api_string_adapter(
- &uri, buffer_size, true);
- api_string_adapter.Close(FPDFAction_GetURIPath(
- doc(), action, api_string_adapter.GetData(), buffer_size));
+ std::string uri = CallPDFiumStringBufferApi(
+ base::BindRepeating(&FPDFAction_GetURIPath, doc(), action),
+ /*check_expected_size=*/true);
+ if (!uri.empty())
dict.Set(pp::Var("uri"), pp::Var(uri));
- }
}
pp::VarArray children;
@@ -2328,6 +2367,7 @@ void PDFiumEngine::SetGrayscale(bool grayscale) {
}
void PDFiumEngine::HandleLongPress(const pp::TouchInputEvent& event) {
+ base::AutoReset<bool> handling_long_press_guard(&handling_long_press_, true);
pp::FloatPoint fp =
event.GetTouchByIndex(PP_TOUCHLIST_TYPE_TARGETTOUCHES, 0).position();
pp::Point point;
@@ -2719,7 +2759,8 @@ void PDFiumEngine::LoadForm() {
kFormHighlightColor);
FPDF_SetFormFieldHighlightAlpha(form(), kFormHighlightAlpha);
- if (base::FeatureList::IsEnabled(features::kTabAcrossPDFAnnotations)) {
+ if (base::FeatureList::IsEnabled(features::kTabAcrossPDFAnnotations) &&
+ !client_->IsPrintPreview()) {
static constexpr FPDF_ANNOTATION_SUBTYPE kFocusableAnnotSubtypes[] = {
FPDF_ANNOT_LINK, FPDF_ANNOT_HIGHLIGHT, FPDF_ANNOT_WIDGET};
FPDF_BOOL ret = FPDFAnnot_SetFocusableSubtypes(
@@ -3558,12 +3599,12 @@ void PDFiumEngine::SetSelecting(bool selecting) {
client_->IsSelectingChanged(selecting);
}
-void PDFiumEngine::SetEditMode(bool edit_mode) {
- if (edit_mode_ == edit_mode)
+void PDFiumEngine::EnteredEditMode() {
+ if (edit_mode_)
return;
- edit_mode_ = edit_mode;
- client_->IsEditModeChanged(edit_mode_);
+ edit_mode_ = true;
+ client_->EnteredEditMode();
}
void PDFiumEngine::SetInFormTextArea(bool in_form_text_area) {
@@ -3671,7 +3712,30 @@ void PDFiumEngine::SetSelection(
}
}
-void PDFiumEngine::ScrollIntoView(const pp::Rect& rect) {
+void PDFiumEngine::ScrollFocusedAnnotationIntoView() {
+ FPDF_ANNOTATION annot;
+ int page_index;
+ if (!FORM_GetFocusedAnnot(form(), &page_index, &annot))
+ return;
+
+ ScrollAnnotationIntoView(annot, page_index);
+ FPDFPage_CloseAnnot(annot);
+}
+
+void PDFiumEngine::ScrollAnnotationIntoView(FPDF_ANNOTATION annot,
+ int page_index) {
+ if (!PageIndexInBounds(page_index))
+ return;
+
+ FS_RECTF annot_rect;
+ if (!FPDFAnnot_GetRect(annot, &annot_rect))
+ return;
+
+ pp::Rect rect = pages_[page_index]->PageToScreen(
+ pp::Point(), /*zoom=*/1.0, annot_rect.left, annot_rect.top,
+ annot_rect.right, annot_rect.bottom,
+ layout_.options().default_page_orientation());
+
pp::Rect visible_rect = GetVisibleRect();
if (visible_rect.Contains(rect))
return;
@@ -3778,6 +3842,28 @@ void PDFiumEngine::GetSelection(uint32_t* selection_start_page_index,
}
}
+void PDFiumEngine::LoadDocumentAttachmentInfoList() {
+ DCHECK(document_loaded_);
+
+ int attachment_count = FPDFDoc_GetAttachmentCount(doc());
+ if (attachment_count <= 0)
+ return;
+
+ doc_attachment_info_list_.resize(attachment_count);
+ for (int i = 0; i < attachment_count; ++i) {
+ FPDF_ATTACHMENT attachment = FPDFDoc_GetAttachment(doc(), i);
+ DCHECK(attachment);
+
+ doc_attachment_info_list_[i].name = GetAttachmentName(attachment);
+ doc_attachment_info_list_[i].size_bytes =
+ GetAttachmentFileLengthInBytes(attachment);
+ doc_attachment_info_list_[i].creation_date =
+ GetAttachmentAttribute(attachment, "CreationDate");
+ doc_attachment_info_list_[i].modified_date =
+ GetAttachmentAttribute(attachment, "ModDate");
+ }
+}
+
void PDFiumEngine::LoadDocumentMetadata() {
DCHECK(document_loaded_);
@@ -3793,17 +3879,9 @@ void PDFiumEngine::LoadDocumentMetadata() {
std::string PDFiumEngine::GetMetadataByField(FPDF_BYTESTRING field) const {
DCHECK(doc());
- size_t size =
- FPDF_GetMetaText(doc(), field, /*buffer=*/nullptr, /*buflen=*/0);
- if (size == 0)
- return std::string();
-
- base::string16 value;
- PDFiumAPIStringBufferSizeInBytesAdapter<base::string16> string_adapter(
- &value, size, /*check_expected_size=*/false);
- string_adapter.Close(
- FPDF_GetMetaText(doc(), field, string_adapter.GetData(), size));
- return base::UTF16ToUTF8(value);
+ return base::UTF16ToUTF8(CallPDFiumWideStringBufferApi(
+ base::BindRepeating(&FPDF_GetMetaText, doc(), field),
+ /*check_expected_size=*/false));
}
PdfVersion PDFiumEngine::GetDocumentVersion() const {
@@ -3869,7 +3947,7 @@ bool PDFiumEngine::HandleTabEventWithModifiers(uint32_t modifiers) {
bool PDFiumEngine::HandleTabForward(uint32_t modifiers) {
if (focus_item_type_ == FocusElementType::kNone) {
- focus_item_type_ = FocusElementType::kDocument;
+ UpdateFocusItemType(FocusElementType::kDocument);
return true;
}
@@ -3887,17 +3965,17 @@ bool PDFiumEngine::HandleTabForward(uint32_t modifiers) {
if (did_tab_forward) {
last_focused_page_ = page_index;
- focus_item_type_ = FocusElementType::kPage;
+ UpdateFocusItemType(FocusElementType::kPage);
} else {
last_focused_page_ = -1;
- focus_item_type_ = FocusElementType::kNone;
+ UpdateFocusItemType(FocusElementType::kNone);
}
return did_tab_forward;
}
bool PDFiumEngine::HandleTabBackward(uint32_t modifiers) {
if (focus_item_type_ == FocusElementType::kDocument) {
- focus_item_type_ = FocusElementType::kNone;
+ UpdateFocusItemType(FocusElementType::kNone);
return false;
}
@@ -3915,7 +3993,7 @@ bool PDFiumEngine::HandleTabBackward(uint32_t modifiers) {
if (did_tab_backward) {
last_focused_page_ = page_index;
- focus_item_type_ = FocusElementType::kPage;
+ UpdateFocusItemType(FocusElementType::kPage);
} else {
// No focusable annotation found in pages. Possible scenarios:
// Case 1: |focus_item_type_| is None. Since no object in any page can take
@@ -3928,11 +4006,11 @@ bool PDFiumEngine::HandleTabBackward(uint32_t modifiers) {
case FocusElementType::kNone:
did_tab_backward = true;
last_focused_page_ = -1;
- focus_item_type_ = FocusElementType::kDocument;
+ UpdateFocusItemType(FocusElementType::kDocument);
KillFormFocus();
break;
case FocusElementType::kDocument:
- focus_item_type_ = FocusElementType::kNone;
+ UpdateFocusItemType(FocusElementType::kNone);
break;
default:
NOTREACHED();
@@ -3942,6 +4020,16 @@ bool PDFiumEngine::HandleTabBackward(uint32_t modifiers) {
return did_tab_backward;
}
+void PDFiumEngine::UpdateFocusItemType(FocusElementType focus_item_type) {
+ if (focus_item_type_ == focus_item_type)
+ return;
+ if (focus_item_type_ == FocusElementType::kDocument)
+ client_->DocumentFocusChanged(false);
+ focus_item_type_ = focus_item_type;
+ if (focus_item_type_ == FocusElementType::kDocument)
+ client_->DocumentFocusChanged(true);
+}
+
#if defined(PDF_ENABLE_XFA)
void PDFiumEngine::UpdatePageCount() {
InvalidateAllPages();
diff --git a/chromium/pdf/pdfium/pdfium_engine.h b/chromium/pdf/pdfium/pdfium_engine.h
index cf507e8d469..2261904a961 100644
--- a/chromium/pdf/pdfium/pdfium_engine.h
+++ b/chromium/pdf/pdfium/pdfium_engine.h
@@ -17,6 +17,7 @@
#include "base/optional.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
+#include "pdf/document_attachment_info.h"
#include "pdf/document_layout.h"
#include "pdf/document_loader.h"
#include "pdf/document_metadata.h"
@@ -99,6 +100,7 @@ class PDFiumEngine : public PDFEngine,
void RotateClockwise() override;
void RotateCounterclockwise() override;
void SetTwoUpView(bool enable) override;
+ void DisplayAnnotations(bool display) override;
pp::Size ApplyDocumentLayout(const DocumentLayout::Options& options) override;
std::string GetSelectedText() override;
bool CanEditText() override;
@@ -113,6 +115,8 @@ class PDFiumEngine : public PDFEngine,
std::string GetLinkAtPosition(const pp::Point& point) override;
bool HasPermission(DocumentPermission permission) const override;
void SelectAll() override;
+ const std::vector<DocumentAttachmentInfo>& GetDocumentAttachmentInfoList()
+ const override;
const DocumentMetadata& GetDocumentMetadata() const override;
int GetNumberOfPages() override;
pp::VarArray GetBookmarks() override;
@@ -564,7 +568,7 @@ class PDFiumEngine : public PDFEngine,
const pp::Point& global_point);
// Set if the document has any local edits.
- void SetEditMode(bool edit_mode);
+ void EnteredEditMode();
// Navigates to a link destination depending on the type of destination.
// Returns false if |area| is not a link.
@@ -580,12 +584,18 @@ class PDFiumEngine : public PDFEngine,
void SetSelection(const PP_PdfPageCharacterIndex& selection_start_index,
const PP_PdfPageCharacterIndex& selection_end_index);
- // Given |rect| in document coordinates, scroll the |rect| into view if not
- // already in view.
- void ScrollIntoView(const pp::Rect& rect);
+ // Scroll the current focused annotation into view if not already in view.
+ void ScrollFocusedAnnotationIntoView();
+
+ // Given |annot|, scroll the |annot| into view if not already in view.
+ void ScrollAnnotationIntoView(FPDF_ANNOTATION annot, int page_index);
void OnFocusedAnnotationUpdated(FPDF_ANNOTATION annot, int page_index);
+ // Read the attachments' information inside the PDF document, and set
+ // |doc_attachment_info_list_|. To be called after the document is loaded.
+ void LoadDocumentAttachmentInfoList();
+
// Fetches and populates the fields of |doc_metadata_|. To be called after the
// document is loaded.
void LoadDocumentMetadata();
@@ -606,6 +616,10 @@ class PDFiumEngine : public PDFEngine,
bool HandleTabForward(uint32_t modifiers);
bool HandleTabBackward(uint32_t modifiers);
+ // Updates the currently focused object stored in |focus_item_type_|. Notifies
+ // |client_| about document focus change, if any.
+ void UpdateFocusItemType(FocusElementType focus_item_type);
+
void UpdateLinkUnderCursor(const std::string& target_url);
void SetLinkUnderCursorForAnnotation(FPDF_ANNOTATION annot, int page_index);
@@ -710,6 +724,9 @@ class PDFiumEngine : public PDFEngine,
// Timer for touch long press detection.
base::OneShotTimer touch_timer_;
+ // Set to true when handling long touch press.
+ bool handling_long_press_ = false;
+
// Set to true when updating plugin focus.
bool updating_focus_ = false;
@@ -792,6 +809,9 @@ class PDFiumEngine : public PDFEngine,
// Shadow matrix for generating the page shadow bitmap.
std::unique_ptr<draw_utils::ShadowMatrix> page_shadow_;
+ // A list of information of document attachments.
+ std::vector<DocumentAttachmentInfo> doc_attachment_info_list_;
+
// Stores parsed document metadata.
DocumentMetadata doc_metadata_;
diff --git a/chromium/pdf/pdfium/pdfium_engine_unittest.cc b/chromium/pdf/pdfium/pdfium_engine_unittest.cc
index 4aa29dd8451..978be627972 100644
--- a/chromium/pdf/pdfium/pdfium_engine_unittest.cc
+++ b/chromium/pdf/pdfium/pdfium_engine_unittest.cc
@@ -4,8 +4,10 @@
#include "pdf/pdfium/pdfium_engine.h"
+#include "base/strings/utf_string_conversions.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.h"
+#include "pdf/document_attachment_info.h"
#include "pdf/document_layout.h"
#include "pdf/document_metadata.h"
#include "pdf/pdf_features.h"
@@ -185,6 +187,53 @@ TEST_F(PDFiumEngineTest, ApplyDocumentLayoutAvoidsInfiniteLoop) {
CompareSize({343, 1463}, engine->ApplyDocumentLayout(options));
}
+TEST_F(PDFiumEngineTest, GetDocumentAttachmentInfo) {
+ NiceMock<MockTestClient> client;
+ std::unique_ptr<PDFiumEngine> engine =
+ InitializeEngine(&client, FILE_PATH_LITERAL("embedded_attachments.pdf"));
+ ASSERT_TRUE(engine);
+
+ const std::vector<DocumentAttachmentInfo>& attachments =
+ engine->GetDocumentAttachmentInfoList();
+ ASSERT_EQ(3u, attachments.size());
+
+ {
+ const DocumentAttachmentInfo& attachment = attachments[0];
+ EXPECT_EQ("1.txt", base::UTF16ToUTF8(attachment.name));
+ EXPECT_EQ(4u, attachment.size_bytes);
+ EXPECT_EQ("D:20170712214438-07'00'",
+ base::UTF16ToUTF8(attachment.creation_date));
+ EXPECT_EQ("D:20160115091400", base::UTF16ToUTF8(attachment.modified_date));
+ }
+
+ {
+ const DocumentAttachmentInfo& attachment = attachments[1];
+ EXPECT_EQ("attached.pdf", base::UTF16ToUTF8(attachment.name));
+ EXPECT_EQ(5869u, attachment.size_bytes);
+ EXPECT_EQ("D:20170712214443-07'00'",
+ base::UTF16ToUTF8(attachment.creation_date));
+ EXPECT_EQ("D:20170712214410", base::UTF16ToUTF8(attachment.modified_date));
+ }
+
+ {
+ // Test attachments with no creation date or last modified date.
+ const DocumentAttachmentInfo& attachment = attachments[2];
+ EXPECT_EQ("附錄.txt", base::UTF16ToUTF8(attachment.name));
+ EXPECT_EQ(5u, attachment.size_bytes);
+ EXPECT_THAT(attachment.creation_date, IsEmpty());
+ EXPECT_THAT(attachment.modified_date, IsEmpty());
+ }
+}
+
+TEST_F(PDFiumEngineTest, NoDocumentAttachmentInfo) {
+ NiceMock<MockTestClient> client;
+ std::unique_ptr<PDFiumEngine> engine =
+ InitializeEngine(&client, FILE_PATH_LITERAL("hello_world2.pdf"));
+ ASSERT_TRUE(engine);
+
+ EXPECT_EQ(0u, engine->GetDocumentAttachmentInfoList().size());
+}
+
TEST_F(PDFiumEngineTest, GetDocumentMetadata) {
NiceMock<MockTestClient> client;
std::unique_ptr<PDFiumEngine> engine =
@@ -229,6 +278,17 @@ TEST_F(PDFiumEngineTest, GetBadPdfVersion) {
} // namespace
+class TabbingTestClient : public TestClient {
+ public:
+ TabbingTestClient() = default;
+ ~TabbingTestClient() override = default;
+ TabbingTestClient(const TabbingTestClient&) = delete;
+ TabbingTestClient& operator=(const TabbingTestClient&) = delete;
+
+ // Mock PDFEngine::Client methods.
+ MOCK_METHOD1(DocumentFocusChanged, void(bool));
+};
+
class PDFiumEngineTabbingTest : public PDFiumTestBase {
public:
PDFiumEngineTabbingTest() = default;
@@ -269,6 +329,10 @@ class PDFiumEngineTabbingTest : public PDFiumTestBase {
return engine->link_under_cursor_;
}
+ void ScrollFocusedAnnotationIntoView(PDFiumEngine* engine) {
+ engine->ScrollFocusedAnnotationIntoView();
+ }
+
protected:
base::test::TaskEnvironment task_environment_{
base::test::TaskEnvironment::TimeSource::MOCK_TIME};
@@ -378,13 +442,20 @@ TEST_F(PDFiumEngineTabbingTest, TabbingForwardTest) {
* ++ Page 2
* ++++ Annotation
*/
- TestClient client;
+ TabbingTestClient client;
std::unique_ptr<PDFiumEngine> engine = InitializeEngine(
&client, FILE_PATH_LITERAL("annotation_form_fields.pdf"));
ASSERT_TRUE(engine);
ASSERT_EQ(2, engine->GetNumberOfPages());
+ static constexpr bool kExpectedFocusState[] = {true, false};
+ {
+ InSequence sequence;
+ for (auto focused : kExpectedFocusState)
+ EXPECT_CALL(client, DocumentFocusChanged(focused));
+ }
+
ASSERT_EQ(PDFiumEngine::FocusElementType::kNone,
GetFocusedElementType(engine.get()));
EXPECT_EQ(-1, GetLastFocusedPage(engine.get()));
@@ -423,13 +494,20 @@ TEST_F(PDFiumEngineTabbingTest, TabbingBackwardTest) {
* ++ Page 2
* ++++ Annotation
*/
- TestClient client;
+ TabbingTestClient client;
std::unique_ptr<PDFiumEngine> engine = InitializeEngine(
&client, FILE_PATH_LITERAL("annotation_form_fields.pdf"));
ASSERT_TRUE(engine);
ASSERT_EQ(2, engine->GetNumberOfPages());
+ static constexpr bool kExpectedFocusState[] = {true, false};
+ {
+ InSequence sequence;
+ for (auto focused : kExpectedFocusState)
+ EXPECT_CALL(client, DocumentFocusChanged(focused));
+ }
+
ASSERT_EQ(PDFiumEngine::FocusElementType::kNone,
GetFocusedElementType(engine.get()));
EXPECT_EQ(-1, GetLastFocusedPage(engine.get()));
@@ -512,13 +590,20 @@ TEST_F(PDFiumEngineTabbingTest, NoFocusableItemTabbingTest) {
* ++ Page 1
* ++ Page 2
*/
- TestClient client;
+ TabbingTestClient client;
std::unique_ptr<PDFiumEngine> engine =
InitializeEngine(&client, FILE_PATH_LITERAL("hello_world2.pdf"));
ASSERT_TRUE(engine);
ASSERT_EQ(2, engine->GetNumberOfPages());
+ static constexpr bool kExpectedFocusState[] = {true, false, true, false};
+ {
+ InSequence sequence;
+ for (auto focused : kExpectedFocusState)
+ EXPECT_CALL(client, DocumentFocusChanged(focused));
+ }
+
ASSERT_EQ(PDFiumEngine::FocusElementType::kNone,
GetFocusedElementType(engine.get()));
EXPECT_EQ(-1, GetLastFocusedPage(engine.get()));
@@ -552,13 +637,20 @@ TEST_F(PDFiumEngineTabbingTest, RestoringDocumentFocusTest) {
* ++ Page 2
* ++++ Annotation
*/
- TestClient client;
+ TabbingTestClient client;
std::unique_ptr<PDFiumEngine> engine = InitializeEngine(
&client, FILE_PATH_LITERAL("annotation_form_fields.pdf"));
ASSERT_TRUE(engine);
ASSERT_EQ(2, engine->GetNumberOfPages());
+ static constexpr bool kExpectedFocusState[] = {true, false, true};
+ {
+ InSequence sequence;
+ for (auto focused : kExpectedFocusState)
+ EXPECT_CALL(client, DocumentFocusChanged(focused));
+ }
+
EXPECT_EQ(PDFiumEngine::FocusElementType::kNone,
GetFocusedElementType(engine.get()));
EXPECT_EQ(-1, GetLastFocusedPage(engine.get()));
@@ -590,13 +682,20 @@ TEST_F(PDFiumEngineTabbingTest, RestoringAnnotFocusTest) {
* ++ Page 2
* ++++ Annotation
*/
- TestClient client;
+ TabbingTestClient client;
std::unique_ptr<PDFiumEngine> engine = InitializeEngine(
&client, FILE_PATH_LITERAL("annotation_form_fields.pdf"));
ASSERT_TRUE(engine);
ASSERT_EQ(2, engine->GetNumberOfPages());
+ static constexpr bool kExpectedFocusState[] = {true, false};
+ {
+ InSequence sequence;
+ for (auto focused : kExpectedFocusState)
+ EXPECT_CALL(client, DocumentFocusChanged(focused));
+ }
+
EXPECT_EQ(PDFiumEngine::FocusElementType::kNone,
GetFocusedElementType(engine.get()));
EXPECT_EQ(-1, GetLastFocusedPage(engine.get()));
@@ -773,4 +872,51 @@ TEST_F(PDFiumEngineTabbingTest, MaintainViewportWhenFocusIsUpdated) {
EXPECT_EQ(0, GetLastFocusedPage(engine.get()));
}
+TEST_F(PDFiumEngineTabbingTest, ScrollFocusedAnnotationIntoView) {
+ StrictMock<ScrollingTestClient> client;
+ std::unique_ptr<PDFiumEngine> engine = InitializeEngine(
+ &client, FILE_PATH_LITERAL("annotation_form_fields.pdf"));
+ ASSERT_TRUE(engine);
+ ASSERT_EQ(2, engine->GetNumberOfPages());
+ engine->PluginSizeUpdated(pp::Size(60, 40));
+
+ {
+ InSequence sequence;
+ static constexpr PP_Point kScrollValues[] = {{510, 478}, {510, 478}};
+
+ for (const auto& scroll_value : kScrollValues) {
+ EXPECT_CALL(client, ScrollToY(scroll_value.y, false))
+ .WillOnce(Invoke([&engine, &scroll_value]() {
+ engine->ScrolledToYPosition(scroll_value.y);
+ }));
+ EXPECT_CALL(client, ScrollToX(scroll_value.x))
+ .WillOnce(Invoke([&engine, &scroll_value]() {
+ engine->ScrolledToXPosition(scroll_value.x);
+ }));
+ }
+ }
+
+ EXPECT_EQ(PDFiumEngine::FocusElementType::kNone,
+ GetFocusedElementType(engine.get()));
+ EXPECT_EQ(-1, GetLastFocusedPage(engine.get()));
+
+ // Tabbing to bring the document into focus.
+ ASSERT_TRUE(HandleTabEvent(engine.get(), 0));
+ EXPECT_EQ(PDFiumEngine::FocusElementType::kDocument,
+ GetFocusedElementType(engine.get()));
+
+ // Tab to an annotation.
+ ASSERT_TRUE(HandleTabEvent(engine.get(), 0));
+ EXPECT_EQ(PDFiumEngine::FocusElementType::kPage,
+ GetFocusedElementType(engine.get()));
+
+ // Scroll focused annotation out of viewport.
+ static constexpr PP_Point kScrollPosition = {242, 746};
+ engine->ScrolledToXPosition(kScrollPosition.x);
+ engine->ScrolledToYPosition(kScrollPosition.y);
+
+ // Scroll the focused annotation into view.
+ ScrollFocusedAnnotationIntoView(engine.get());
+}
+
} // namespace chrome_pdf
diff --git a/chromium/pdf/pdfium/pdfium_form_filler.cc b/chromium/pdf/pdfium/pdfium_form_filler.cc
index 4a142b4cba5..d85bd2ceef1 100644
--- a/chromium/pdf/pdfium/pdfium_form_filler.cc
+++ b/chromium/pdf/pdfium/pdfium_form_filler.cc
@@ -194,7 +194,7 @@ FPDF_SYSTEMTIME PDFiumFormFiller::Form_GetLocalTime(FPDF_FORMFILLINFO* param) {
// static
void PDFiumFormFiller::Form_OnChange(FPDF_FORMFILLINFO* param) {
PDFiumEngine* engine = GetEngine(param);
- engine->SetEditMode(true);
+ engine->EnteredEditMode();
}
// static
@@ -285,17 +285,8 @@ void PDFiumFormFiller::Form_OnFocusChange(FPDF_FORMFILLINFO* param,
// Maintain viewport if we are updating focus. This is to ensure that we don't
// scroll the focused annotation into view when focus is regained.
- if (!engine->updating_focus_) {
- FS_RECTF annot_rect;
- if (!FPDFAnnot_GetRect(annot, &annot_rect))
- return;
-
- pp::Rect screen_rect = engine->pages_[page_index]->PageToScreen(
- pp::Point(), /*zoom=*/1.0, annot_rect.left, annot_rect.top,
- annot_rect.right, annot_rect.bottom,
- engine->layout_.options().default_page_orientation());
- engine->ScrollIntoView(screen_rect);
- }
+ if (!engine->updating_focus_)
+ engine->ScrollAnnotationIntoView(annot, page_index);
engine->OnFocusedAnnotationUpdated(annot, page_index);
}
diff --git a/chromium/pdf/pdfium/pdfium_page.cc b/chromium/pdf/pdfium/pdfium_page.cc
index 4f5f5af65b8..6f95affddc8 100644
--- a/chromium/pdf/pdfium/pdfium_page.cc
+++ b/chromium/pdf/pdfium/pdfium_page.cc
@@ -186,24 +186,6 @@ bool FloatEquals(float f1, float f2) {
kEpsilonScale * fmaxf(fmaxf(fabsf(f1), fabsf(f2)), kEpsilonScale);
}
-using GetFormFieldPropertyFunction =
- base::RepeatingCallback<unsigned long(unsigned short* buffer,
- unsigned long buflen)>;
-
-// Helper method to fetch string properties of form fields.
-std::string GetFormFieldProperty(GetFormFieldPropertyFunction function) {
- base::string16 data;
- size_t buffer_size = function.Run(nullptr, 0);
- if (buffer_size > 0) {
- PDFiumAPIStringBufferSizeInBytesAdapter<base::string16> api_string_adapter(
- &data, buffer_size, true);
- api_string_adapter.Close(function.Run(
- reinterpret_cast<unsigned short*>(api_string_adapter.GetData()),
- buffer_size));
- }
- return base::UTF16ToUTF8(data);
-}
-
// Count overlaps across text annotations.
template <typename T, typename U>
uint32_t CountOverlaps(const std::vector<T>& first_set,
@@ -472,6 +454,18 @@ PDFiumPage::GetTextRunInfo(int start_char_index) {
info.direction = PP_PRIVATEDIRECTION_NONE;
return info;
}
+
+ // If the first character in a text run is a space, we need to start
+ // |text_run_bounds| from the space character instead of the first
+ // non-space unicode character.
+ pp::FloatRect text_run_bounds =
+ actual_start_char_index > start_char_index
+ ? GetFloatCharRectInPixels(page, text_page, start_char_index)
+ : pp::FloatRect();
+
+ // Pdfium trims more than 1 consecutive spaces to 1 space.
+ DCHECK_LE(actual_start_char_index - start_char_index, 1);
+
int char_index = actual_start_char_index;
// Set text run's style info from the first character of the text run.
@@ -494,8 +488,8 @@ PDFiumPage::GetTextRunInfo(int start_char_index) {
AddCharSizeToAverageCharSize(start_char_rect.Floatsize(), &avg_char_size,
&non_whitespace_chars_count);
- // Add first char to text run.
- pp::FloatRect text_run_bounds = start_char_rect;
+ // Add first non-space char to text run.
+ text_run_bounds = text_run_bounds.Union(start_char_rect);
PP_PrivateDirection char_direction =
GetDirectionFromAngle(FPDFText_GetCharAngle(text_page, char_index));
if (char_index < chars_count)
@@ -676,6 +670,7 @@ PDFiumPage::GetHighlightInfo() {
highlight.bounding_rect.x(), highlight.bounding_rect.y(),
highlight.bounding_rect.width(), highlight.bounding_rect.height());
cur_info.color = highlight.color;
+ cur_info.note_text = highlight.note_text;
highlight_info.push_back(std::move(cur_info));
}
return highlight_info;
@@ -900,16 +895,11 @@ gfx::PointF PDFiumPage::TransformPageToScreenXY(const gfx::PointF& xy) {
PDFiumPage::Area PDFiumPage::GetURITarget(FPDF_ACTION uri_action,
LinkTarget* target) const {
if (target) {
- size_t buffer_size =
- FPDFAction_GetURIPath(engine_->doc(), uri_action, nullptr, 0);
- if (buffer_size > 0) {
- PDFiumAPIStringBufferAdapter<std::string> api_string_adapter(
- &target->url, buffer_size, true);
- void* data = api_string_adapter.GetData();
- size_t bytes_written =
- FPDFAction_GetURIPath(engine_->doc(), uri_action, data, buffer_size);
- api_string_adapter.Close(bytes_written);
- }
+ std::string url = CallPDFiumStringBufferApi(
+ base::BindRepeating(&FPDFAction_GetURIPath, engine_->doc(), uri_action),
+ /*check_expected_size=*/true);
+ if (!url.empty())
+ target->url = url;
}
return WEBLINK_AREA;
}
@@ -956,6 +946,8 @@ void PDFiumPage::PopulateWebLinks() {
ScopedFPDFPageLink links(FPDFLink_LoadWebLinks(GetTextPage()));
int count = FPDFLink_CountWebLinks(links.get());
for (int i = 0; i < count; ++i) {
+ // WARNING: FPDFLink_GetURL() is not compatible with
+ // CallPDFiumWideStringBufferApi().
base::string16 url;
int url_length = FPDFLink_GetURL(links.get(), i, nullptr, 0);
if (url_length > 0) {
@@ -1141,16 +1133,11 @@ void PDFiumPage::PopulateImageAltTextForStructElement(
auto it = marked_content_id_image_map.find(marked_content_id);
if (it != marked_content_id_image_map.end() &&
images_[it->second].alt_text.empty()) {
- size_t buffer_size =
- FPDF_StructElement_GetAltText(current_element, nullptr, 0);
- if (buffer_size > 0) {
- base::string16 alt_text;
- PDFiumAPIStringBufferSizeInBytesAdapter<base::string16>
- api_string_adapter(&alt_text, buffer_size, true);
- api_string_adapter.Close(FPDF_StructElement_GetAltText(
- current_element, api_string_adapter.GetData(), buffer_size));
- images_[it->second].alt_text = base::UTF16ToUTF8(alt_text);
- }
+ images_[it->second].alt_text =
+ base::UTF16ToUTF8(CallPDFiumWideStringBufferApi(
+ base::BindRepeating(&FPDF_StructElement_GetAltText,
+ current_element),
+ /*check_expected_size=*/true));
}
}
int children_count = FPDF_StructElement_CountChildren(current_element);
@@ -1182,11 +1169,7 @@ void PDFiumPage::PopulateAnnotations() {
break;
}
case FPDF_ANNOT_WIDGET: {
- // TODO(crbug.com/1030242): Populate other types of form fields too.
- if (FPDFAnnot_GetFormFieldType(engine_->form(), annot.get()) ==
- FPDF_FORMFIELD_TEXTFIELD) {
- PopulateTextField(annot.get());
- }
+ PopulateFormField(annot.get());
break;
}
default:
@@ -1230,6 +1213,14 @@ void PDFiumPage::PopulateHighlight(FPDF_ANNOTATION annot) {
highlight.color = MakeARGB(255, 255, 255, 0);
}
+ // Retrieve the contents of the popup note associated with highlight.
+ // See table 164 in ISO 32000-1 standard for more details around "Contents"
+ // key in a highlight annotation.
+ static constexpr char kContents[] = "Contents";
+ highlight.note_text = base::UTF16ToUTF8(CallPDFiumWideStringBufferApi(
+ base::BindRepeating(&FPDFAnnot_GetStringValue, annot, kContents),
+ /*check_expected_size=*/true));
+
highlights_.push_back(std::move(highlight));
}
@@ -1239,21 +1230,81 @@ void PDFiumPage::PopulateTextField(FPDF_ANNOTATION annot) {
DCHECK_EQ(FPDFAnnot_GetFormFieldType(form_handle, annot),
FPDF_FORMFIELD_TEXTFIELD);
+ TextField text_field;
+ if (!PopulateFormFieldProperties(annot, &text_field))
+ return;
+
+ text_field.value = base::UTF16ToUTF8(CallPDFiumWideStringBufferApi(
+ base::BindRepeating(&FPDFAnnot_GetFormFieldValue, form_handle, annot),
+ /*check_expected_size=*/true));
+ text_fields_.push_back(std::move(text_field));
+}
+
+void PDFiumPage::PopulateChoiceField(FPDF_ANNOTATION annot) {
+ DCHECK(annot);
+ FPDF_FORMHANDLE form_handle = engine_->form();
+ int form_field_type = FPDFAnnot_GetFormFieldType(form_handle, annot);
+ DCHECK(form_field_type == FPDF_FORMFIELD_LISTBOX ||
+ form_field_type == FPDF_FORMFIELD_COMBOBOX);
+
+ ChoiceField choice_field;
+ if (!PopulateFormFieldProperties(annot, &choice_field))
+ return;
+
+ int options_count = FPDFAnnot_GetOptionCount(form_handle, annot);
+ if (options_count < 0)
+ return;
+
+ choice_field.options.resize(options_count);
+ for (int i = 0; i < options_count; ++i) {
+ choice_field.options[i].name =
+ base::UTF16ToUTF8(CallPDFiumWideStringBufferApi(
+ base::BindRepeating(&FPDFAnnot_GetOptionLabel, form_handle, annot,
+ i),
+ /*check_expected_size=*/true));
+ choice_field.options[i].is_selected =
+ FPDFAnnot_IsOptionSelected(form_handle, annot, i);
+ }
+ choice_fields_.push_back(std::move(choice_field));
+}
+
+void PDFiumPage::PopulateFormField(FPDF_ANNOTATION annot) {
+ DCHECK_EQ(FPDFAnnot_GetSubtype(annot), FPDF_ANNOT_WIDGET);
+ int form_field_type = FPDFAnnot_GetFormFieldType(engine_->form(), annot);
+
+ // TODO(crbug.com/1030242): Populate other types of form fields too.
+ switch (form_field_type) {
+ case FPDF_FORMFIELD_COMBOBOX:
+ case FPDF_FORMFIELD_LISTBOX: {
+ PopulateChoiceField(annot);
+ break;
+ }
+ case FPDF_FORMFIELD_TEXTFIELD: {
+ PopulateTextField(annot);
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+bool PDFiumPage::PopulateFormFieldProperties(FPDF_ANNOTATION annot,
+ FormField* form_field) {
+ DCHECK(annot);
FS_RECTF rect;
if (!FPDFAnnot_GetRect(annot, &rect))
- return;
+ return false;
- TextField text_field;
- // We use the bounding box of the text field as the bounding rect.
- text_field.bounding_rect =
+ // We use the bounding box of the form field as the bounding rect.
+ form_field->bounding_rect =
PageToScreen(pp::Point(), 1.0, rect.left, rect.top, rect.right,
rect.bottom, PageOrientation::kOriginal);
- text_field.value = GetFormFieldProperty(
- base::BindRepeating(FPDFAnnot_GetFormFieldValue, form_handle, annot));
- text_field.name = GetFormFieldProperty(
- base::BindRepeating(FPDFAnnot_GetFormFieldName, form_handle, annot));
- text_field.flags = FPDFAnnot_GetFormFieldFlags(form_handle, annot);
- text_fields_.push_back(std::move(text_field));
+ FPDF_FORMHANDLE form_handle = engine_->form();
+ form_field->name = base::UTF16ToUTF8(CallPDFiumWideStringBufferApi(
+ base::BindRepeating(&FPDFAnnot_GetFormFieldName, form_handle, annot),
+ /*check_expected_size=*/true));
+ form_field->flags = FPDFAnnot_GetFormFieldFlags(form_handle, annot);
+ return true;
}
bool PDFiumPage::GetUnderlyingTextRangeForRect(const pp::FloatRect& rect,
@@ -1385,12 +1436,31 @@ PDFiumPage::Highlight::Highlight(const Highlight& that) = default;
PDFiumPage::Highlight::~Highlight() = default;
+PDFiumPage::FormField::FormField() = default;
+
+PDFiumPage::FormField::FormField(const FormField& that) = default;
+
+PDFiumPage::FormField::~FormField() = default;
+
PDFiumPage::TextField::TextField() = default;
PDFiumPage::TextField::TextField(const TextField& that) = default;
PDFiumPage::TextField::~TextField() = default;
+PDFiumPage::ChoiceFieldOption::ChoiceFieldOption() = default;
+
+PDFiumPage::ChoiceFieldOption::ChoiceFieldOption(
+ const ChoiceFieldOption& that) = default;
+
+PDFiumPage::ChoiceFieldOption::~ChoiceFieldOption() = default;
+
+PDFiumPage::ChoiceField::ChoiceField() = default;
+
+PDFiumPage::ChoiceField::ChoiceField(const ChoiceField& that) = default;
+
+PDFiumPage::ChoiceField::~ChoiceField() = default;
+
// static
uint32_t PDFiumPage::CountLinkHighlightOverlaps(
const std::vector<Link>& links,
diff --git a/chromium/pdf/pdfium/pdfium_page.h b/chromium/pdf/pdfium/pdfium_page.h
index 5a3aefae9da..baaec24e081 100644
--- a/chromium/pdf/pdfium/pdfium_page.h
+++ b/chromium/pdf/pdfium/pdfium_page.h
@@ -178,63 +178,10 @@ class PDFiumPage {
FRIEND_TEST_ALL_PREFIXES(PDFiumPageLinkTest, TestLinkGeneration);
FRIEND_TEST_ALL_PREFIXES(PDFiumPageHighlightTest, TestPopulateHighlights);
FRIEND_TEST_ALL_PREFIXES(PDFiumPageTextFieldTest, TestPopulateTextFields);
+ FRIEND_TEST_ALL_PREFIXES(PDFiumPageChoiceFieldTest, TestPopulateChoiceFields);
FRIEND_TEST_ALL_PREFIXES(PDFiumPageOverlappingTest, CountPartialOverlaps);
FRIEND_TEST_ALL_PREFIXES(PDFiumPageOverlappingTest, CountCompleteOverlaps);
- // Returns a link index if the given character index is over a link, or -1
- // otherwise.
- int GetLink(int char_index, LinkTarget* target);
- // Calculate the locations of any links on the page.
- void CalculateLinks();
- // Populates weblinks on the page.
- void PopulateWebLinks();
- // Populates annotation links on the page.
- void PopulateAnnotationLinks();
- // Calculate the locations of images on the page.
- void CalculateImages();
- // Populate annotations like highlight and text field on the page.
- void PopulateAnnotations();
- // Populate |highlights_| with |annot|.
- void PopulateHighlight(FPDF_ANNOTATION annot);
- // Populate |text_fields_| with |annot|.
- void PopulateTextField(FPDF_ANNOTATION annot);
- // Returns link type and fills target associated with a destination. Returns
- // NONSELECTABLE_AREA if detection failed.
- Area GetDestinationTarget(FPDF_DEST destination, LinkTarget* target);
- // Returns link type and fills target associated with a URI action. Returns
- // NONSELECTABLE_AREA if detection failed.
- Area GetURITarget(FPDF_ACTION uri_action, LinkTarget* target) const;
- // Calculates the set of character indices on which text runs need to be
- // broken for page objects such as links and images.
- void CalculatePageObjectTextRunBreaks();
- // Set text run style information based on a character of the text run.
- void CalculateTextRunStyleInfo(
- int char_index,
- pp::PDF::PrivateAccessibilityTextStyleInfo* style_info);
- // Returns a boolean indicating if the character at index |char_index| has the
- // same text style as the text run.
- bool AreTextStyleEqual(
- int char_index,
- const pp::PDF::PrivateAccessibilityTextStyleInfo& style);
-
- // Key : Marked content id for the image element as specified in the
- // struct tree.
- // Value : Index of image in the |images_| vector.
- using MarkedContentIdToImageMap = std::map<int, size_t>;
- // Traverses the entire struct tree of the page recursively and extracts the
- // alt text from struct tree elements corresponding to the marked content IDs
- // present in |marked_content_id_image_map|.
- void PopulateImageAltText(
- const MarkedContentIdToImageMap& marked_content_id_image_map);
- // Traverses a struct element and its sub-tree recursively and extracts the
- // alt text from struct elements corresponding to the marked content IDs
- // present in |marked_content_id_image_map|. Uses |visited_elements| to guard
- // against malformed struct trees.
- void PopulateImageAltTextForStructElement(
- const MarkedContentIdToImageMap& marked_content_id_image_map,
- FPDF_STRUCTELEMENT current_element,
- std::set<FPDF_STRUCTELEMENT>* visited_elements);
-
class ScopedUnloadPreventer {
public:
explicit ScopedUnloadPreventer(PDFiumPage* page);
@@ -284,25 +231,114 @@ class PDFiumPage {
// Color of the highlight in ARGB. Alpha is stored in the first 8 MSBs. RGB
// follows after it with each using 8 bytes.
uint32_t color;
+
+ // Text of the popup note associated with highlight.
+ std::string note_text;
+ };
+
+ // Represents a form field within the page.
+ struct FormField {
+ FormField();
+ FormField(const FormField& other);
+ ~FormField();
+
+ pp::Rect bounding_rect;
+ // Represents the name of form field as defined in the field dictionary.
+ std::string name;
+ // Represents the flags of form field as defined in the field dictionary.
+ int flags;
};
// Represents a text field within the page.
- struct TextField {
+ struct TextField : FormField {
TextField();
TextField(const TextField& other);
~TextField();
- // Represents the name of form field as defined in the field dictionary.
- std::string name;
std::string value;
- pp::Rect bounding_rect;
- // Represents the flags of form field as defined in the field dictionary.
- int flags;
};
+ // Represents a choice field option.
+ struct ChoiceFieldOption {
+ ChoiceFieldOption();
+ ChoiceFieldOption(const ChoiceFieldOption& other);
+ ~ChoiceFieldOption();
+
+ std::string name;
+ bool is_selected;
+ };
+
+ // Represents a choice field within the page.
+ struct ChoiceField : FormField {
+ ChoiceField();
+ ChoiceField(const ChoiceField& other);
+ ~ChoiceField();
+
+ std::vector<ChoiceFieldOption> options;
+ };
+
+ // Returns a link index if the given character index is over a link, or -1
+ // otherwise.
+ int GetLink(int char_index, LinkTarget* target);
+ // Calculate the locations of any links on the page.
+ void CalculateLinks();
+ // Populates weblinks on the page.
+ void PopulateWebLinks();
+ // Populates annotation links on the page.
+ void PopulateAnnotationLinks();
+ // Calculate the locations of images on the page.
+ void CalculateImages();
+ // Populate annotations like highlight and text field on the page.
+ void PopulateAnnotations();
+ // Populate |highlights_| with |annot|.
+ void PopulateHighlight(FPDF_ANNOTATION annot);
+ // Populate |text_fields_| with |annot|.
+ void PopulateTextField(FPDF_ANNOTATION annot);
+ // Populate |choice_fields_| with |annot|.
+ void PopulateChoiceField(FPDF_ANNOTATION annot);
+ // Populate form fields like text field and choice field on the page.
+ void PopulateFormField(FPDF_ANNOTATION annot);
+ // Returns link type and fills target associated with a destination. Returns
+ // NONSELECTABLE_AREA if detection failed.
+ Area GetDestinationTarget(FPDF_DEST destination, LinkTarget* target);
+ // Returns link type and fills target associated with a URI action. Returns
+ // NONSELECTABLE_AREA if detection failed.
+ Area GetURITarget(FPDF_ACTION uri_action, LinkTarget* target) const;
+ // Calculates the set of character indices on which text runs need to be
+ // broken for page objects such as links and images.
+ void CalculatePageObjectTextRunBreaks();
+ // Set text run style information based on a character of the text run.
+ void CalculateTextRunStyleInfo(
+ int char_index,
+ pp::PDF::PrivateAccessibilityTextStyleInfo* style_info);
+ // Returns a boolean indicating if the character at index |char_index| has the
+ // same text style as the text run.
+ bool AreTextStyleEqual(
+ int char_index,
+ const pp::PDF::PrivateAccessibilityTextStyleInfo& style);
+
+ // Key : Marked content id for the image element as specified in the
+ // struct tree.
+ // Value : Index of image in the |images_| vector.
+ using MarkedContentIdToImageMap = std::map<int, size_t>;
+ // Traverses the entire struct tree of the page recursively and extracts the
+ // alt text from struct tree elements corresponding to the marked content IDs
+ // present in |marked_content_id_image_map|.
+ void PopulateImageAltText(
+ const MarkedContentIdToImageMap& marked_content_id_image_map);
+ // Traverses a struct element and its sub-tree recursively and extracts the
+ // alt text from struct elements corresponding to the marked content IDs
+ // present in |marked_content_id_image_map|. Uses |visited_elements| to guard
+ // against malformed struct trees.
+ void PopulateImageAltTextForStructElement(
+ const MarkedContentIdToImageMap& marked_content_id_image_map,
+ FPDF_STRUCTELEMENT current_element,
+ std::set<FPDF_STRUCTELEMENT>* visited_elements);
static uint32_t CountLinkHighlightOverlaps(
const std::vector<Link>& links,
const std::vector<Highlight>& highlights);
+ bool PopulateFormFieldProperties(FPDF_ANNOTATION annot,
+ FormField* form_field);
PDFiumEngine* engine_;
ScopedFPDFPage page_;
@@ -317,6 +353,7 @@ class PDFiumPage {
bool calculated_annotations_ = false;
std::vector<Highlight> highlights_;
std::vector<TextField> text_fields_;
+ std::vector<ChoiceField> choice_fields_;
bool logged_overlapping_annotations_ = false;
bool calculated_page_object_text_run_breaks_ = false;
// The set of character indices on which text runs need to be broken for page
diff --git a/chromium/pdf/pdfium/pdfium_page_unittest.cc b/chromium/pdf/pdfium/pdfium_page_unittest.cc
index 7906515599d..fae64ca8f2e 100644
--- a/chromium/pdf/pdfium/pdfium_page_unittest.cc
+++ b/chromium/pdf/pdfium/pdfium_page_unittest.cc
@@ -8,6 +8,8 @@
#include <vector>
#include "base/check.h"
+#include "base/optional.h"
+#include "base/strings/string_util.h"
#include "base/test/gtest_util.h"
#include "pdf/pdfium/pdfium_engine.h"
#include "pdf/pdfium/pdfium_test_base.h"
@@ -234,6 +236,80 @@ TEST_F(PDFiumPageImageTest, TestImageAltText) {
using PDFiumPageTextTest = PDFiumTestBase;
+TEST_F(PDFiumPageTextTest, TestTextRunBounds) {
+ TestClient client;
+ std::unique_ptr<PDFiumEngine> engine = InitializeEngine(
+ &client, FILE_PATH_LITERAL("leading_trailing_spaces_per_text_run.pdf"));
+ ASSERT_TRUE(engine);
+
+ constexpr int kFirstRunStartIndex = 0;
+ constexpr int kFirstRunEndIndex = 20;
+ constexpr int kPageIndex = 0;
+ base::Optional<pp::PDF::PrivateAccessibilityTextRunInfo> text_run_info_1 =
+ engine->GetTextRunInfo(kPageIndex, kFirstRunStartIndex);
+ ASSERT_TRUE(text_run_info_1.has_value());
+
+ const auto& actual_text_run_1 = text_run_info_1.value();
+ EXPECT_EQ(21u, actual_text_run_1.len);
+
+ EXPECT_TRUE(base::IsUnicodeWhitespace(
+ engine->GetCharUnicode(kPageIndex, kFirstRunStartIndex)));
+ pp::FloatRect text_run_bounds = actual_text_run_1.bounds;
+ EXPECT_TRUE(text_run_bounds.Contains(
+ engine->GetCharBounds(kPageIndex, kFirstRunStartIndex)));
+
+ // Last non-space character should fall in the bounding box of the text run.
+ // Text run looks like this:
+ // " Hello, world! \r\n "<17 characters><first Tj>
+ // " \r\n "<4 characters><second Tj>
+ // " "<1 character><third Tj starting spaces>
+ // Finally generated text run: " Hello, world! \r\n \r\n "
+ constexpr int kFirstRunLastNonSpaceCharIndex = 13;
+ EXPECT_FALSE(base::IsUnicodeWhitespace(
+ engine->GetCharUnicode(kPageIndex, kFirstRunLastNonSpaceCharIndex)));
+ EXPECT_TRUE(text_run_bounds.Contains(
+ engine->GetCharBounds(kPageIndex, kFirstRunLastNonSpaceCharIndex)));
+
+ EXPECT_TRUE(base::IsUnicodeWhitespace(
+ engine->GetCharUnicode(kPageIndex, kFirstRunEndIndex)));
+ pp::FloatRect end_char_rect =
+ engine->GetCharBounds(kPageIndex, kFirstRunEndIndex);
+ EXPECT_FALSE(text_run_bounds.Contains(end_char_rect));
+ // Equals to the length of the previous text run.
+ constexpr int kSecondRunStartIndex = 21;
+ constexpr int kSecondRunEndIndex = 36;
+ // Test the properties of second text run.
+ // Note: The leading spaces in second text run are accounted for in the end
+ // of first text run. Hence we won't see a space leading the second text run.
+ base::Optional<pp::PDF::PrivateAccessibilityTextRunInfo> text_run_info_2 =
+ engine->GetTextRunInfo(kPageIndex, kSecondRunStartIndex);
+ ASSERT_TRUE(text_run_info_2.has_value());
+
+ const auto& actual_text_run_2 = text_run_info_2.value();
+ EXPECT_EQ(16u, actual_text_run_2.len);
+
+ EXPECT_FALSE(base::IsUnicodeWhitespace(
+ engine->GetCharUnicode(kPageIndex, kSecondRunStartIndex)));
+ text_run_bounds = actual_text_run_2.bounds;
+ EXPECT_TRUE(text_run_bounds.Contains(
+ engine->GetCharBounds(kPageIndex, kSecondRunStartIndex)));
+
+ // Last non-space character should fall in the bounding box of the text run.
+ // Text run looks like this:
+ // "Goodbye, world! "<19 characters><first Tj>
+ // Finally generated text run: "Goodbye, world! "
+ constexpr int kSecondRunLastNonSpaceCharIndex = 35;
+ EXPECT_FALSE(base::IsUnicodeWhitespace(
+ engine->GetCharUnicode(kPageIndex, kSecondRunLastNonSpaceCharIndex)));
+ EXPECT_TRUE(text_run_bounds.Contains(
+ engine->GetCharBounds(kPageIndex, kSecondRunLastNonSpaceCharIndex)));
+
+ EXPECT_TRUE(base::IsUnicodeWhitespace(
+ engine->GetCharUnicode(kPageIndex, kSecondRunEndIndex)));
+ EXPECT_FALSE(text_run_bounds.Contains(
+ engine->GetCharBounds(kPageIndex, kSecondRunEndIndex)));
+}
+
TEST_F(PDFiumPageTextTest, GetTextRunInfo) {
TestClient client;
std::unique_ptr<PDFiumEngine> engine =
@@ -333,7 +409,7 @@ TEST_F(PDFiumPageTextTest, TestHighlightTextRunInfo) {
{7,
PP_MakeFloatRectFromXYWH(106.66666f, 198.66667f, 73.333336f, 18.666672f),
PP_PrivateDirection::PP_PRIVATEDIRECTION_LTR, kExpectedStyle},
- {2, PP_MakeFloatRectFromXYWH(188.0f, 202.66667f, 9.333333f, 14.666667f),
+ {2, PP_MakeFloatRectFromXYWH(181.33333f, 192.0f, 16.0f, 25.333344f),
PP_PrivateDirection::PP_PRIVATEDIRECTION_NONE, kExpectedStyle},
{2,
PP_MakeFloatRectFromXYWH(198.66667f, 202.66667f, 21.333328f, 10.666672f),
@@ -437,6 +513,94 @@ TEST_F(PDFiumPageTextFieldTest, TestPopulateTextFields) {
}
}
+using PDFiumPageChoiceFieldTest = PDFiumTestBase;
+
+TEST_F(PDFiumPageChoiceFieldTest, TestPopulateChoiceFields) {
+ struct ExpectedChoiceFieldOption {
+ const char* name;
+ bool is_selected;
+ };
+
+ struct ExpectedChoiceField {
+ const char* name;
+ std::vector<struct ExpectedChoiceFieldOption> options;
+ pp::Rect bounding_rect;
+ int flags;
+ };
+
+ static const ExpectedChoiceField kExpectedChoiceFields[] = {
+ {"Listbox_SingleSelect",
+ {{"Foo", false}, {"Bar", false}, {"Qux", false}},
+ {138, 296, 135, 41},
+ 0},
+ {"Combo1",
+ {{"Apple", false}, {"Banana", true}, {"Cherry", false}},
+ {138, 230, 135, 41},
+ 131072},
+ {"Listbox_ReadOnly",
+ {{"Dog", false}, {"Elephant", false}, {"Frog", false}},
+ {138, 96, 135, 41},
+ 1},
+ {"Listbox_MultiSelectMultipleIndices",
+ {
+ {"Albania", false},
+ {"Belgium", true},
+ {"Croatia", false},
+ {"Denmark", true},
+ {"Estonia", false},
+ },
+ {138, 430, 135, 41},
+ 2097152},
+ {"Listbox_MultiSelectMultipleValues",
+ {
+ {"Alpha", false},
+ {"Beta", false},
+ {"Gamma", true},
+ {"Delta", false},
+ {"Epsilon", true},
+ },
+ {138, 496, 135, 41},
+ 2097152},
+ {"Listbox_MultiSelectMultipleMismatch",
+ {
+ {"Alligator", true},
+ {"Bear", false},
+ {"Cougar", true},
+ {"Deer", false},
+ {"Echidna", false},
+ },
+ {138, 563, 135, 41},
+ 2097152}};
+
+ TestClient client;
+ std::unique_ptr<PDFiumEngine> engine =
+ InitializeEngine(&client, FILE_PATH_LITERAL("form_choice_fields.pdf"));
+ ASSERT_TRUE(engine);
+ ASSERT_EQ(1, engine->GetNumberOfPages());
+
+ PDFiumPage* page = GetPDFiumPageForTest(engine.get(), 0);
+ ASSERT_TRUE(page);
+ page->PopulateAnnotations();
+ size_t choice_fields_count = page->choice_fields_.size();
+ ASSERT_EQ(base::size(kExpectedChoiceFields), choice_fields_count);
+
+ for (size_t i = 0; i < choice_fields_count; ++i) {
+ EXPECT_EQ(kExpectedChoiceFields[i].name, page->choice_fields_[i].name);
+ size_t choice_field_options_count = page->choice_fields_[i].options.size();
+ ASSERT_EQ(base::size(kExpectedChoiceFields[i].options),
+ choice_field_options_count);
+ for (size_t j = 0; j < choice_field_options_count; ++j) {
+ EXPECT_EQ(kExpectedChoiceFields[i].options[j].name,
+ page->choice_fields_[i].options[j].name);
+ EXPECT_EQ(kExpectedChoiceFields[i].options[j].is_selected,
+ page->choice_fields_[i].options[j].is_selected);
+ }
+ CompareRect(kExpectedChoiceFields[i].bounding_rect,
+ page->choice_fields_[i].bounding_rect);
+ EXPECT_EQ(kExpectedChoiceFields[i].flags, page->choice_fields_[i].flags);
+ }
+}
+
using PDFiumPageOverlappingTest = PDFiumTestBase;
// The following scenarios are covered across both test cases:
diff --git a/chromium/pdf/pdfium/pdfium_permissions.cc b/chromium/pdf/pdfium/pdfium_permissions.cc
index db3c98032b7..b24c6f42a58 100644
--- a/chromium/pdf/pdfium/pdfium_permissions.cc
+++ b/chromium/pdf/pdfium/pdfium_permissions.cc
@@ -4,6 +4,8 @@
#include "pdf/pdfium/pdfium_permissions.h"
+#include "base/notreached.h"
+
namespace chrome_pdf {
// static
diff --git a/chromium/pdf/pdfium/pdfium_print.cc b/chromium/pdf/pdfium/pdfium_print.cc
index 5cb79dce728..be5dd656dda 100644
--- a/chromium/pdf/pdfium/pdfium_print.cc
+++ b/chromium/pdf/pdfium/pdfium_print.cc
@@ -9,11 +9,11 @@
#include <utility>
#include "base/strings/string_number_conversions.h"
-#include "pdf/geometry_conversions.h"
#include "pdf/pdf_transform.h"
#include "pdf/pdfium/pdfium_engine.h"
#include "pdf/pdfium/pdfium_mem_buffer_file_read.h"
#include "pdf/pdfium/pdfium_mem_buffer_file_write.h"
+#include "pdf/ppapi_migration/geometry_conversions.h"
#include "ppapi/c/dev/ppp_printing_dev.h"
#include "ppapi/c/private/ppp_pdf.h"
#include "printing/nup_parameters.h"
diff --git a/chromium/pdf/pdfium/pdfium_test_base.cc b/chromium/pdf/pdfium/pdfium_test_base.cc
index 95c48c11c9b..b220fb92535 100644
--- a/chromium/pdf/pdfium/pdfium_test_base.cc
+++ b/chromium/pdf/pdfium/pdfium_test_base.cc
@@ -103,10 +103,11 @@ PDFiumTestBase::InitializeEngineWithoutLoading(
void PDFiumTestBase::InitializePDFium() {
FPDF_LIBRARY_CONFIG config;
- config.version = 2;
+ config.version = 3;
config.m_pUserFontPaths = nullptr;
config.m_pIsolate = nullptr;
config.m_v8EmbedderSlot = 0;
+ config.m_pPlatform = nullptr;
FPDF_InitLibraryWithConfig(&config);
}
diff --git a/chromium/pdf/ppapi_migration/README.md b/chromium/pdf/ppapi_migration/README.md
new file mode 100644
index 00000000000..f6426f94eba
--- /dev/null
+++ b/chromium/pdf/ppapi_migration/README.md
@@ -0,0 +1,5 @@
+# PPAPI migration utilities
+
+This directory contains utilities for bridging from legacy APIs during the PDF
+viewer's [migration from Pepper](https://crbug.com/702993). The utilities should
+be designed for easy removal once the migration is complete.
diff --git a/chromium/pdf/geometry_conversions.cc b/chromium/pdf/ppapi_migration/geometry_conversions.cc
index 37a7bb0c358..a6399e04938 100644
--- a/chromium/pdf/geometry_conversions.cc
+++ b/chromium/pdf/ppapi_migration/geometry_conversions.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "pdf/geometry_conversions.h"
+#include "pdf/ppapi_migration/geometry_conversions.h"
#include "ppapi/c/pp_rect.h"
#include "ppapi/c/pp_size.h"
diff --git a/chromium/pdf/geometry_conversions.h b/chromium/pdf/ppapi_migration/geometry_conversions.h
index d9220034511..8806207abc7 100644
--- a/chromium/pdf/geometry_conversions.h
+++ b/chromium/pdf/ppapi_migration/geometry_conversions.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef PDF_GEOMETRY_CONVERSIONS_H_
-#define PDF_GEOMETRY_CONVERSIONS_H_
+#ifndef PDF_PPAPI_MIGRATION_GEOMETRY_CONVERSIONS_H_
+#define PDF_PPAPI_MIGRATION_GEOMETRY_CONVERSIONS_H_
struct PP_Rect;
struct PP_Size;
@@ -20,4 +20,4 @@ gfx::Size SizeFromPPSize(const PP_Size& pp_size);
} // namespace chrome_pdf
-#endif // PDF_GEOMETRY_CONVERSIONS_H_
+#endif // PDF_PPAPI_MIGRATION_GEOMETRY_CONVERSIONS_H_
diff --git a/chromium/pdf/preview_mode_client.cc b/chromium/pdf/preview_mode_client.cc
index cf355047c84..ea3cdac0669 100644
--- a/chromium/pdf/preview_mode_client.cc
+++ b/chromium/pdf/preview_mode_client.cc
@@ -146,8 +146,7 @@ void PreviewModeClient::FormTextFieldFocusChange(bool in_focus) {
}
bool PreviewModeClient::IsPrintPreview() {
- NOTREACHED();
- return false;
+ return true;
}
float PreviewModeClient::GetToolbarHeightInScreenCoords() {