summaryrefslogtreecommitdiff
path: root/chromium/pdf/out_of_process_instance.cc
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/out_of_process_instance.cc
parent7b5b123ac58f58ffde0f4f6e488bcd09aa4decd3 (diff)
downloadqtwebengine-chromium-85-based.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/out_of_process_instance.cc')
-rw-r--r--chromium/pdf/out_of_process_instance.cc614
1 files changed, 350 insertions, 264 deletions
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());