summaryrefslogtreecommitdiff
path: root/chromium/pdf
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2022-02-02 12:21:57 +0100
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2022-02-12 08:13:00 +0000
commit606d85f2a5386472314d39923da28c70c60dc8e7 (patch)
treea8f4d7bf997f349f45605e6058259fba0630e4d7 /chromium/pdf
parent5786336dda477d04fb98483dca1a5426eebde2d7 (diff)
downloadqtwebengine-chromium-606d85f2a5386472314d39923da28c70c60dc8e7.tar.gz
BASELINE: Update Chromium to 96.0.4664.181
Change-Id: I762cd1da89d73aa6313b4a753fe126c34833f046 Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/pdf')
-rw-r--r--chromium/pdf/BUILD.gn11
-rw-r--r--chromium/pdf/COMMON_METADATA3
-rw-r--r--chromium/pdf/DEPS3
-rw-r--r--chromium/pdf/DIR_METADATA4
-rw-r--r--chromium/pdf/OWNERS1
-rw-r--r--chromium/pdf/document_layout.cc7
-rw-r--r--chromium/pdf/document_layout.h15
-rw-r--r--chromium/pdf/document_layout_unittest.cc71
-rw-r--r--chromium/pdf/features.gni2
-rw-r--r--chromium/pdf/mojom/pdf.mojom21
-rw-r--r--chromium/pdf/out_of_process_instance.cc196
-rw-r--r--chromium/pdf/out_of_process_instance.h20
-rw-r--r--chromium/pdf/pdf.h3
-rw-r--r--chromium/pdf/pdf_accessibility_action_handler.h1
-rw-r--r--chromium/pdf/pdf_utils/dates.cc4
-rw-r--r--chromium/pdf/pdf_view_plugin_base.cc327
-rw-r--r--chromium/pdf/pdf_view_plugin_base.h154
-rw-r--r--chromium/pdf/pdf_view_plugin_base_unittest.cc666
-rw-r--r--chromium/pdf/pdf_view_web_plugin.cc307
-rw-r--r--chromium/pdf/pdf_view_web_plugin.h75
-rw-r--r--chromium/pdf/pdf_view_web_plugin_unittest.cc485
-rw-r--r--chromium/pdf/pdfium/DEPS1
-rw-r--r--chromium/pdf/pdfium/pdfium_assert_matching_enums.cc2
-rw-r--r--chromium/pdf/pdfium/pdfium_engine.cc22
-rw-r--r--chromium/pdf/pdfium/pdfium_engine_unittest.cc93
-rw-r--r--chromium/pdf/pdfium/pdfium_form_filler.cc122
-rw-r--r--chromium/pdf/pdfium/pdfium_form_filler.h47
-rw-r--r--chromium/pdf/pdfium/pdfium_form_filler_unittest.cc54
-rw-r--r--chromium/pdf/pdfium/pdfium_print_unittest.cc2
-rw-r--r--chromium/pdf/ppapi_migration/graphics.cc2
-rw-r--r--chromium/pdf/ppapi_migration/graphics_unittest.cc2
-rw-r--r--chromium/pdf/ppapi_migration/input_event_conversions.cc17
-rw-r--r--chromium/pdf/ppapi_migration/url_loader.cc1
-rw-r--r--chromium/pdf/url_loader_wrapper_impl.cc2
34 files changed, 2021 insertions, 722 deletions
diff --git a/chromium/pdf/BUILD.gn b/chromium/pdf/BUILD.gn
index 2ebc8400391..a06ffd9e682 100644
--- a/chromium/pdf/BUILD.gn
+++ b/chromium/pdf/BUILD.gn
@@ -175,6 +175,7 @@ if (enable_pdf) {
public_deps = [
"//printing/mojom",
"//skia",
+ "//v8",
]
deps = [
@@ -333,7 +334,6 @@ if (enable_pdf) {
"//base",
"//build:chromeos_buildflags",
"//net",
- "//pdf:buildflags",
"//ppapi/cpp:objects",
"//ppapi/cpp/private:internal_module",
"//skia",
@@ -341,6 +341,7 @@ if (enable_pdf) {
"//third_party/blink/public/common:headers",
"//ui/base",
"//ui/base/cursor/mojom:cursor_type",
+ "//url",
]
}
@@ -401,6 +402,8 @@ if (enable_pdf) {
"test/test_document_loader.h",
"test/test_helpers.cc",
"test/test_helpers.h",
+ "test/test_pdfium_engine.cc",
+ "test/test_pdfium_engine.h",
]
configs += [ ":common" ]
@@ -410,9 +413,11 @@ if (enable_pdf) {
":ppapi_migration",
"//base",
"//ppapi/cpp:objects",
+ "//testing/gmock",
"//testing/gtest",
- "//ui/gfx:geometry_skia",
+ "//third_party/blink/public/common:headers",
"//ui/gfx/range",
+ "//ui/latency:latency",
]
}
@@ -498,9 +503,11 @@ if (enable_pdf) {
"//third_party/blink/public/common:headers",
"//third_party/pdfium",
"//ui/base",
+ "//ui/events/blink:blink",
"//ui/gfx:test_support",
"//ui/gfx/geometry",
"//ui/gfx/range",
+ "//v8",
]
if (v8_use_external_startup_data) {
diff --git a/chromium/pdf/COMMON_METADATA b/chromium/pdf/COMMON_METADATA
new file mode 100644
index 00000000000..bfb1239ef3e
--- /dev/null
+++ b/chromium/pdf/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+ component: "Internals>Plugins>PDF"
+} \ No newline at end of file
diff --git a/chromium/pdf/DEPS b/chromium/pdf/DEPS
index 5bd03ea7fde..afd5d53460d 100644
--- a/chromium/pdf/DEPS
+++ b/chromium/pdf/DEPS
@@ -14,11 +14,12 @@ include_rules = [
"+ui/display",
"+ui/events",
"+ui/gfx",
- "+v8/include/v8.h"
+ "+v8/include",
]
specific_include_rules = {
".*_unittest.*\.cc": [
"+cc/test",
+ "+ui/latency/latency_info.h",
],
}
diff --git a/chromium/pdf/DIR_METADATA b/chromium/pdf/DIR_METADATA
index 8734c2bd51c..7ec54c5dcff 100644
--- a/chromium/pdf/DIR_METADATA
+++ b/chromium/pdf/DIR_METADATA
@@ -6,6 +6,4 @@
# For the schema of this file, see Metadata message:
# https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto
-monorail {
- component: "Internals>Plugins>PDF"
-} \ No newline at end of file
+mixins: "//pdf/COMMON_METADATA"
diff --git a/chromium/pdf/OWNERS b/chromium/pdf/OWNERS
index 79ab573f6cd..3955287c58c 100644
--- a/chromium/pdf/OWNERS
+++ b/chromium/pdf/OWNERS
@@ -1,6 +1,5 @@
set noparent
dhoss@chromium.org
-dsinclair@chromium.org
kmoon@chromium.org
thestig@chromium.org
diff --git a/chromium/pdf/document_layout.cc b/chromium/pdf/document_layout.cc
index f13d7d066e9..756e1cb3869 100644
--- a/chromium/pdf/document_layout.cc
+++ b/chromium/pdf/document_layout.cc
@@ -16,6 +16,7 @@ namespace chrome_pdf {
namespace {
+constexpr char kDirection[] = "direction";
constexpr char kDefaultPageOrientation[] = "defaultPageOrientation";
constexpr char kTwoUpViewEnabled[] = "twoUpViewEnabled";
@@ -51,6 +52,7 @@ DocumentLayout::Options::~Options() = default;
base::Value DocumentLayout::Options::ToValue() const {
base::Value dictionary(base::Value::Type::DICTIONARY);
+ dictionary.SetIntKey(kDirection, direction_);
dictionary.SetIntKey(kDefaultPageOrientation,
static_cast<int32_t>(default_page_orientation_));
dictionary.SetBoolKey(kTwoUpViewEnabled,
@@ -61,6 +63,11 @@ base::Value DocumentLayout::Options::ToValue() const {
void DocumentLayout::Options::FromValue(const base::Value& value) {
DCHECK(value.is_dict());
+ int32_t direction = value.FindIntKey(kDirection).value();
+ DCHECK_GE(direction, base::i18n::UNKNOWN_DIRECTION);
+ DCHECK_LE(direction, base::i18n::TEXT_DIRECTION_MAX);
+ direction_ = static_cast<base::i18n::TextDirection>(direction);
+
int32_t default_page_orientation =
value.FindIntKey(kDefaultPageOrientation).value();
DCHECK_GE(default_page_orientation,
diff --git a/chromium/pdf/document_layout.h b/chromium/pdf/document_layout.h
index 4bd6cadf658..ec57a3f0bf0 100644
--- a/chromium/pdf/document_layout.h
+++ b/chromium/pdf/document_layout.h
@@ -9,6 +9,7 @@
#include <vector>
#include "base/check_op.h"
+#include "base/i18n/rtl.h"
#include "pdf/draw_utils/coordinates.h"
#include "pdf/page_orientation.h"
#include "ui/gfx/geometry/rect.h"
@@ -46,8 +47,9 @@ class DocumentLayout final {
~Options();
friend bool operator==(const Options& lhs, const Options& rhs) {
- return lhs.page_spread() == rhs.page_spread() &&
- lhs.default_page_orientation() == rhs.default_page_orientation();
+ return lhs.direction() == rhs.direction() &&
+ lhs.default_page_orientation() == rhs.default_page_orientation() &&
+ lhs.page_spread() == rhs.page_spread();
}
friend bool operator!=(const Options& lhs, const Options& rhs) {
@@ -60,6 +62,14 @@ class DocumentLayout final {
// Deserializes layout options from a base::Value.
void FromValue(const base::Value& value);
+ // Page layout direction. This is tied to the direction of the user's UI,
+ // rather than the direction of individual pages.
+ base::i18n::TextDirection direction() const { return direction_; }
+
+ void set_direction(base::i18n::TextDirection direction) {
+ direction_ = direction;
+ }
+
PageOrientation default_page_orientation() const {
return default_page_orientation_;
}
@@ -76,6 +86,7 @@ class DocumentLayout final {
void set_page_spread(PageSpread spread) { page_spread_ = spread; }
private:
+ base::i18n::TextDirection direction_ = base::i18n::UNKNOWN_DIRECTION;
PageOrientation default_page_orientation_ = PageOrientation::kOriginal;
PageSpread page_spread_ = PageSpread::kOneUp;
};
diff --git a/chromium/pdf/document_layout_unittest.cc b/chromium/pdf/document_layout_unittest.cc
index b10e6e353ef..3b420d108a3 100644
--- a/chromium/pdf/document_layout_unittest.cc
+++ b/chromium/pdf/document_layout_unittest.cc
@@ -4,6 +4,11 @@
#include "pdf/document_layout.h"
+#include "base/i18n/rtl.h"
+#include "base/test/values_test_util.h"
+#include "base/values.h"
+#include "pdf/page_orientation.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/size.h"
@@ -18,34 +23,43 @@ class DocumentLayoutOptionsTest : public testing::Test {
};
TEST_F(DocumentLayoutOptionsTest, DefaultConstructor) {
+ EXPECT_EQ(options_.direction(), base::i18n::UNKNOWN_DIRECTION);
EXPECT_EQ(options_.default_page_orientation(), PageOrientation::kOriginal);
EXPECT_EQ(options_.page_spread(), DocumentLayout::PageSpread::kOneUp);
}
TEST_F(DocumentLayoutOptionsTest, CopyConstructor) {
+ options_.set_direction(base::i18n::RIGHT_TO_LEFT);
options_.RotatePagesClockwise();
options_.set_page_spread(DocumentLayout::PageSpread::kTwoUpOdd);
DocumentLayout::Options copy(options_);
+ EXPECT_EQ(copy.direction(), base::i18n::RIGHT_TO_LEFT);
EXPECT_EQ(copy.default_page_orientation(), PageOrientation::kClockwise90);
EXPECT_EQ(copy.page_spread(), DocumentLayout::PageSpread::kTwoUpOdd);
+ options_.set_direction(base::i18n::LEFT_TO_RIGHT);
options_.RotatePagesClockwise();
options_.set_page_spread(DocumentLayout::PageSpread::kOneUp);
+ EXPECT_EQ(copy.direction(), base::i18n::RIGHT_TO_LEFT);
EXPECT_EQ(copy.default_page_orientation(), PageOrientation::kClockwise90);
EXPECT_EQ(copy.page_spread(), DocumentLayout::PageSpread::kTwoUpOdd);
}
TEST_F(DocumentLayoutOptionsTest, CopyAssignment) {
+ options_.set_direction(base::i18n::RIGHT_TO_LEFT);
options_.RotatePagesClockwise();
options_.set_page_spread(DocumentLayout::PageSpread::kTwoUpOdd);
DocumentLayout::Options copy = options_;
+ EXPECT_EQ(copy.direction(), base::i18n::RIGHT_TO_LEFT);
EXPECT_EQ(copy.default_page_orientation(), PageOrientation::kClockwise90);
EXPECT_EQ(copy.page_spread(), DocumentLayout::PageSpread::kTwoUpOdd);
+ options_.set_direction(base::i18n::LEFT_TO_RIGHT);
options_.RotatePagesClockwise();
options_.set_page_spread(DocumentLayout::PageSpread::kOneUp);
+ EXPECT_EQ(copy.direction(), base::i18n::RIGHT_TO_LEFT);
EXPECT_EQ(copy.default_page_orientation(), PageOrientation::kClockwise90);
EXPECT_EQ(copy.page_spread(), DocumentLayout::PageSpread::kTwoUpOdd);
}
@@ -56,6 +70,12 @@ TEST_F(DocumentLayoutOptionsTest, Equals) {
DocumentLayout::Options copy;
EXPECT_TRUE(copy == options_);
+ options_.set_direction(base::i18n::RIGHT_TO_LEFT);
+ EXPECT_FALSE(copy == options_);
+
+ copy.set_direction(base::i18n::RIGHT_TO_LEFT);
+ EXPECT_TRUE(copy == options_);
+
options_.RotatePagesClockwise();
EXPECT_FALSE(copy == options_);
@@ -73,12 +93,6 @@ TEST_F(DocumentLayoutOptionsTest, Equals) {
copy.set_page_spread(DocumentLayout::PageSpread::kTwoUpOdd);
EXPECT_TRUE(copy == options_);
-
- options_.set_page_spread(DocumentLayout::PageSpread::kOneUp);
- EXPECT_FALSE(copy == options_);
-
- copy.set_page_spread(DocumentLayout::PageSpread::kOneUp);
- EXPECT_TRUE(copy == options_);
}
TEST_F(DocumentLayoutOptionsTest, NotEquals) {
@@ -96,6 +110,51 @@ TEST_F(DocumentLayoutOptionsTest, NotEquals) {
EXPECT_FALSE(copy != options_);
}
+TEST_F(DocumentLayoutOptionsTest, ToValueDefault) {
+ base::Value value = options_.ToValue();
+
+ EXPECT_THAT(value, base::test::IsJson(R"({
+ "direction": 0,
+ "defaultPageOrientation": 0,
+ "twoUpViewEnabled": false,
+ })"));
+}
+
+TEST_F(DocumentLayoutOptionsTest, ToValueModified) {
+ options_.set_direction(base::i18n::LEFT_TO_RIGHT);
+ options_.RotatePagesClockwise();
+ options_.set_page_spread(DocumentLayout::PageSpread::kTwoUpOdd);
+ base::Value value = options_.ToValue();
+
+ EXPECT_THAT(value, base::test::IsJson(R"({
+ "direction": 2,
+ "defaultPageOrientation": 1,
+ "twoUpViewEnabled": true,
+ })"));
+}
+
+TEST_F(DocumentLayoutOptionsTest, FromValueDefault) {
+ options_.FromValue(base::test::ParseJson(R"({
+ "direction": 0,
+ "defaultPageOrientation": 0,
+ "twoUpViewEnabled": false,
+ })"));
+
+ EXPECT_EQ(options_, DocumentLayout::Options());
+}
+
+TEST_F(DocumentLayoutOptionsTest, FromValueModified) {
+ options_.FromValue(base::test::ParseJson(R"({
+ "direction": 2,
+ "defaultPageOrientation": 1,
+ "twoUpViewEnabled": true,
+ })"));
+
+ EXPECT_EQ(options_.direction(), base::i18n::LEFT_TO_RIGHT);
+ EXPECT_EQ(options_.default_page_orientation(), PageOrientation::kClockwise90);
+ EXPECT_EQ(options_.page_spread(), DocumentLayout::PageSpread::kTwoUpOdd);
+}
+
TEST_F(DocumentLayoutOptionsTest, RotatePagesClockwise) {
options_.RotatePagesClockwise();
EXPECT_EQ(options_.default_page_orientation(), PageOrientation::kClockwise90);
diff --git a/chromium/pdf/features.gni b/chromium/pdf/features.gni
index b66bc626fa3..67ce26d6189 100644
--- a/chromium/pdf/features.gni
+++ b/chromium/pdf/features.gni
@@ -2,8 +2,8 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+import("//ash/webui/media_app_ui/media_app_ui.gni")
import("//build/config/chromecast_build.gni")
-import("//chromeos/components/media_app_ui/media_app_ui.gni")
# Most build code won't need to include this file. Instead you can
# unconditionally depend on "//pdf" which will be a no-op when PDF support is
diff --git a/chromium/pdf/mojom/pdf.mojom b/chromium/pdf/mojom/pdf.mojom
index a6cc7415d4a..413fc74dd2e 100644
--- a/chromium/pdf/mojom/pdf.mojom
+++ b/chromium/pdf/mojom/pdf.mojom
@@ -20,6 +20,23 @@ interface PdfListener {
SetSelectionBounds(gfx.mojom.PointF base, gfx.mojom.PointF extent);
};
+// Renderer-side interface to access the PDF extension.
+// The browser passes the remote for this interface to the PDF renderer
+// associated with the PDF extension.
+interface PdfFindInPage {
+ // Sets the find-in-page tickmarks in the PDF extension UI.
+ SetTickmarks(array<gfx.mojom.Rect> tickmark);
+};
+
+// Renderer-side interface to retrieve the PdfFindInPage remote for a specific
+// RFH from a PDF extension. Only used by the browser to facilitate PDF renderer
+// to PDF extension communication.
+interface PdfFindInPageFactory {
+ // Retrieves the remote to pass to the PDF renderer.
+ GetPdfFindInPage() => (pending_remote<PdfFindInPage> find_remote);
+};
+
+// Browser-side interface shared by PDF plugins and PDF renderers.
interface PdfService {
SetListener(pending_remote<PdfListener> client);
@@ -39,4 +56,8 @@ interface PdfService {
// Notifies the embedder know the plugin can handle save commands internally.
SetPluginCanSave(bool can_save);
+
+ // Retrieves the PdfFindInPage remote. Only used by PDF renderers.
+ [Sync]
+ GetPdfFindInPage() => (pending_remote<PdfFindInPage> find_remote);
};
diff --git a/chromium/pdf/out_of_process_instance.cc b/chromium/pdf/out_of_process_instance.cc
index d2a44fc43bb..a341d085c1f 100644
--- a/chromium/pdf/out_of_process_instance.cc
+++ b/chromium/pdf/out_of_process_instance.cc
@@ -9,18 +9,21 @@
#include <string.h>
#include <algorithm>
+#include <iterator>
#include <list>
#include <memory>
+#include <string>
#include <utility>
#include "base/bind.h"
#include "base/callback.h"
#include "base/location.h"
-#include "base/logging.h"
#include "base/memory/weak_ptr.h"
#include "base/notreached.h"
#include "base/numerics/safe_conversions.h"
+#include "base/strings/strcat.h"
#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_piece.h"
#include "base/strings/string_util.h"
#include "base/time/time.h"
#include "base/values.h"
@@ -29,7 +32,6 @@
#include "net/base/escape.h"
#include "pdf/accessibility.h"
#include "pdf/accessibility_structs.h"
-#include "pdf/buildflags.h"
#include "pdf/document_attachment_info.h"
#include "pdf/document_metadata.h"
#include "pdf/pdfium/pdfium_engine.h"
@@ -71,6 +73,7 @@
#include "ui/gfx/geometry/point_f.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/size.h"
+#include "url/gurl.h"
#if defined(OS_LINUX) || defined(OS_CHROMEOS)
#include "pdf/ppapi_migration/pdfium_font_linux.h"
@@ -80,9 +83,6 @@ namespace chrome_pdf {
namespace {
-constexpr base::TimeDelta kFindResultCooldown =
- base::TimeDelta::FromMilliseconds(100);
-
constexpr char kPPPPdfInterface[] = PPP_PDF_INTERFACE_1;
PP_Var GetLinkAtPosition(PP_Instance instance, PP_Point point) {
@@ -443,44 +443,33 @@ bool OutOfProcessInstance::Init(uint32_t argc,
pp::Var document_url_var = pp::URLUtil_Dev::Get()->GetDocumentURL(this);
if (!document_url_var.is_string())
return false;
-
- // Check if the PDF is being loaded in the PDF chrome extension. We only allow
- // the plugin to be loaded in the extension and print preview to avoid
- // exposing sensitive APIs directly to external websites.
- //
- // This is enforced before launching the plugin process (see
- // ChromeContentBrowserClient::ShouldAllowPluginCreation), so below we just do
- // a CHECK as a defense-in-depth.
- std::string document_url = document_url_var.AsString();
- base::StringPiece document_url_piece(document_url);
- set_is_print_preview(IsPrintPreviewUrl(document_url_piece));
- ValidateDocumentUrl(document_url_piece);
+ GURL document_url(document_url_var.AsString());
// Allow the plugin to handle find requests.
SetPluginToHandleFindRequests();
text_input_ = std::make_unique<pp::TextInput_Dev>(this);
- PDFiumFormFiller::ScriptOption script_option =
- PDFiumFormFiller::DefaultScriptOption();
- bool has_edits = false;
const char* src_url = nullptr;
const char* original_url = nullptr;
const char* top_level_url = nullptr;
+ bool full_frame = false;
+ SkColor background_color = SK_ColorTRANSPARENT;
+ PDFiumFormFiller::ScriptOption script_option =
+ PDFiumFormFiller::DefaultScriptOption();
+ bool has_edits = false;
for (uint32_t i = 0; i < argc; ++i) {
- if (strcmp(argn[i], "original-url") == 0) {
- original_url = argv[i];
- } else if (strcmp(argn[i], "src") == 0) {
+ if (strcmp(argn[i], "src") == 0) {
src_url = argv[i];
+ } else if (strcmp(argn[i], "original-url") == 0) {
+ original_url = argv[i];
} else if (strcmp(argn[i], "top-level-url") == 0) {
top_level_url = argv[i];
} else if (strcmp(argn[i], "full-frame") == 0) {
- set_full_frame(true);
+ full_frame = true;
} else if (strcmp(argn[i], "background-color") == 0) {
- SkColor background_color;
if (!base::StringToUint(argv[i], &background_color))
return false;
- SetBackgroundColor(background_color);
} else if (strcmp(argn[i], "javascript") == 0) {
if (strcmp(argv[i], "allow") != 0)
script_option = PDFiumFormFiller::ScriptOption::kNoJavaScript;
@@ -495,27 +484,14 @@ bool OutOfProcessInstance::Init(uint32_t argc,
if (!original_url)
original_url = src_url;
- InitializeEngine(std::make_unique<PDFiumEngine>(this, script_option));
-
- // 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
- // it know the url to load. By not loading here we avoid loading the same
- // document twice.
- if (IsPrintPreview())
- return true;
-
- LoadUrl(src_url, /*is_print_preview=*/false);
- set_url(original_url);
-
- // Not all edits go through the PDF plugin's form filler. The plugin instance
- // can be restarted by exiting annotation mode on ChromeOS, which can set the
- // document to an edited state.
- set_edit_mode(has_edits);
-#if !BUILDFLAG(ENABLE_INK)
- DCHECK(!edit_mode());
-#endif // !BUILDFLAG(ENABLE_INK)
-
pp::PDF::SetCrashData(this, original_url, top_level_url);
+ InitializeBase(std::make_unique<PDFiumEngine>(this, script_option),
+ /*embedder_origin=*/document_url.GetOrigin().spec(),
+ /*src_url=*/src_url,
+ /*original_url=*/original_url,
+ /*full_frame=*/full_frame,
+ /*background_color=*/background_color,
+ /*has_edits=*/has_edits);
return true;
}
@@ -532,16 +508,9 @@ bool OutOfProcessInstance::HandleInputEvent(const pp::InputEvent& event) {
}
void OutOfProcessInstance::DidChangeView(const pp::View& view) {
- UpdateGeometryOnViewChanged(RectFromPPRect(view.GetRect()),
- view.GetDeviceScale());
-
- if (IsPrintPreview() && !stop_scrolling()) {
- set_scroll_position(PointFromPPPoint(view.GetScrollOffset()));
- UpdateScroll();
- }
-
- // Scrolling in the main PDF Viewer UI is already handled by
- // HandleUpdateScrollMessage().
+ const gfx::Rect new_plugin_rect = gfx::ScaleToEnclosingRectSafe(
+ RectFromPPRect(view.GetRect()), view.GetDeviceScale());
+ UpdateGeometryOnPluginRectChanged(new_plugin_rect, view.GetDeviceScale());
}
void OutOfProcessInstance::DidChangeFocus(bool has_focus) {
@@ -670,30 +639,15 @@ bool OutOfProcessInstance::IsPrintScalingDisabled() {
bool OutOfProcessInstance::StartFind(const std::string& text,
bool case_sensitive) {
- engine()->StartFind(text, case_sensitive);
- return true;
+ return PdfViewPluginBase::StartFind(text, case_sensitive);
}
void OutOfProcessInstance::SelectFindResult(bool forward) {
- engine()->SelectFindResult(forward);
+ PdfViewPluginBase::SelectFindResult(forward);
}
void OutOfProcessInstance::StopFind() {
- engine()->StopFind();
- tickmarks_.clear();
- SetTickmarks(tickmarks_);
-}
-
-void OutOfProcessInstance::DidOpen(std::unique_ptr<UrlLoader> loader,
- int32_t result) {
- if (result == PP_OK) {
- if (!engine()->HandleDocumentLoad(std::move(loader), GetURL())) {
- set_document_load_state(DocumentLoadState::kLoading);
- DocumentLoadFailed();
- }
- } else if (result != PP_ERROR_ABORTED) { // Can happen in tests.
- DocumentLoadFailed();
- }
+ PdfViewPluginBase::StopFind();
}
void OutOfProcessInstance::SendMessage(base::Value message) {
@@ -735,41 +689,6 @@ void OutOfProcessInstance::UpdateCursor(ui::mojom::CursorType new_cursor_type) {
pp::ImageData().pp_resource(), nullptr);
}
-void OutOfProcessInstance::UpdateTickMarks(
- const std::vector<gfx::Rect>& tickmarks) {
- float inverse_scale = 1.0f / device_scale();
- tickmarks_.clear();
- tickmarks_.reserve(tickmarks.size());
- for (auto& tickmark : tickmarks) {
- tickmarks_.emplace_back(
- PPRectFromRect(gfx::ScaleToEnclosingRect(tickmark, inverse_scale)));
- }
-}
-
-void OutOfProcessInstance::NotifyNumberOfFindResultsChanged(int total,
- bool final_result) {
- // We don't want to spam the renderer with too many updates to the number of
- // find results. Don't send an update if we sent one too recently. If it's the
- // final update, we always send it though.
- if (final_result) {
- NumberOfFindResultsChanged(total, final_result);
- SetTickmarks(tickmarks_);
- return;
- }
-
- if (recently_sent_find_update_)
- return;
-
- NumberOfFindResultsChanged(total, final_result);
- SetTickmarks(tickmarks_);
- recently_sent_find_update_ = true;
- ScheduleTaskOnMainThread(
- FROM_HERE,
- base::BindOnce(&OutOfProcessInstance::ResetRecentlySentFindUpdate,
- weak_factory_.GetWeakPtr()),
- /*result=*/0, kFindResultCooldown);
-}
-
void OutOfProcessInstance::NotifySelectedFindResultChanged(
int current_find_index) {
DCHECK_GE(current_find_index, -1);
@@ -797,24 +716,6 @@ std::string OutOfProcessInstance::Prompt(const std::string& question,
return result.is_string() ? result.AsString() : std::string();
}
-void OutOfProcessInstance::SubmitForm(const std::string& url,
- const void* data,
- int length) {
- UrlRequest request;
- request.url = url;
- request.method = "POST";
- request.body.assign(static_cast<const char*>(data), length);
-
- form_loader_ = CreateUrlLoaderInternal();
- form_loader_->Open(request, base::BindOnce(&OutOfProcessInstance::FormDidOpen,
- weak_factory_.GetWeakPtr()));
-}
-
-void OutOfProcessInstance::FormDidOpen(int32_t result) {
- // TODO(crbug.com/719344): Process response.
- LOG_IF(ERROR, result != PP_OK) << "FormDidOpen failed: " << result;
-}
-
std::vector<PDFEngine::Client::SearchStringResult>
OutOfProcessInstance::SearchString(const char16_t* string,
const char16_t* term,
@@ -851,10 +752,6 @@ void OutOfProcessInstance::SetLastPluginInstance() {
#endif
}
-void OutOfProcessInstance::ResetRecentlySentFindUpdate(int32_t /* unused */) {
- recently_sent_find_update_ = false;
-}
-
Image OutOfProcessInstance::GetPluginImageData() const {
return Image(pepper_image_data_);
}
@@ -902,6 +799,20 @@ void OutOfProcessInstance::SetAccessibilityViewportInfo(
pp::PDF::SetAccessibilityViewportInfo(this, &pp_viewport_info);
}
+void OutOfProcessInstance::NotifyFindResultsChanged(int total,
+ bool final_result) {
+ NumberOfFindResultsChanged(total, final_result);
+}
+
+void OutOfProcessInstance::NotifyFindTickmarks(
+ const std::vector<gfx::Rect>& tickmarks) {
+ std::vector<pp::Rect> pp_tickmarks;
+ pp_tickmarks.reserve(tickmarks.size());
+ std::transform(tickmarks.begin(), tickmarks.end(),
+ std::back_inserter(pp_tickmarks), PPRectFromRect);
+ SetTickmarks(pp_tickmarks);
+}
+
void OutOfProcessInstance::SetPluginCanSave(bool can_save) {
pp::PDF::SetPluginCanSave(this, can_save);
}
@@ -916,6 +827,29 @@ std::unique_ptr<UrlLoader> OutOfProcessInstance::CreateUrlLoaderInternal() {
return loader;
}
+std::string OutOfProcessInstance::RewriteRequestUrl(
+ base::StringPiece url) const {
+ if (IsPrintPreview()) {
+ // TODO(crbug.com/1238829): This is a workaround for Pepper not supporting
+ // chrome-untrusted://print/ URLs. Pepper issues requests through the
+ // embedder's URL loaders, but a WebUI loader only supports subresource
+ // requests to the same scheme (so chrome: only can request chrome: URLs,
+ // and chrome-untrusted: only can request chrome-untrusted: URLs).
+ //
+ // To work around this (for the Pepper plugin only), we'll issue
+ // chrome-untrusted://print/ requests to the equivalent chrome://print/ URL,
+ // since both schemes support the same PDF URLs.
+ if (base::StartsWith(url, kChromeUntrustedPrintHost)) {
+ return base::StrCat(
+ {kChromePrintHost, url.substr(kChromeUntrustedPrintHost.size())});
+ }
+
+ NOTREACHED();
+ }
+
+ return PdfViewPluginBase::RewriteRequestUrl(url);
+}
+
void OutOfProcessInstance::SetSelectedText(const std::string& selected_text) {
pp::PDF::SetSelectedText(this, selected_text.c_str());
}
diff --git a/chromium/pdf/out_of_process_instance.h b/chromium/pdf/out_of_process_instance.h
index f0f9f075af7..d9ed221b3c2 100644
--- a/chromium/pdf/out_of_process_instance.h
+++ b/chromium/pdf/out_of_process_instance.h
@@ -89,17 +89,12 @@ class OutOfProcessInstance : public PdfViewPluginBase,
// PdfViewPluginBase:
void UpdateCursor(ui::mojom::CursorType new_cursor_type) override;
- void UpdateTickMarks(const std::vector<gfx::Rect>& tickmarks) override;
- void NotifyNumberOfFindResultsChanged(int total, bool final_result) override;
void NotifySelectedFindResultChanged(int current_find_index) override;
void CaretChanged(const gfx::Rect& caret_rect) override;
void Alert(const std::string& message) override;
bool Confirm(const std::string& message) override;
std::string Prompt(const std::string& question,
const std::string& default_answer) override;
- void SubmitForm(const std::string& url,
- const void* data,
- int length) override;
std::vector<SearchStringResult> SearchString(const char16_t* string,
const char16_t* term,
bool case_sensitive) override;
@@ -121,7 +116,7 @@ class OutOfProcessInstance : public PdfViewPluginBase,
// PdfViewPluginBase:
base::WeakPtr<PdfViewPluginBase> GetWeakPtr() override;
std::unique_ptr<UrlLoader> CreateUrlLoaderInternal() override;
- void DidOpen(std::unique_ptr<UrlLoader> loader, int32_t result) override;
+ std::string RewriteRequestUrl(base::StringPiece url) const override;
void SendMessage(base::Value message) override;
void SaveAs() override;
void InitImageData(const gfx::Size& size) override;
@@ -134,6 +129,8 @@ class OutOfProcessInstance : public PdfViewPluginBase,
AccessibilityPageObjects page_objects) override;
void SetAccessibilityViewportInfo(
const AccessibilityViewportInfo& viewport_info) override;
+ void NotifyFindResultsChanged(int total, bool final_result) override;
+ void NotifyFindTickmarks(const std::vector<gfx::Rect>& tickmarks) override;
void SetContentRestrictions(int content_restrictions) override;
void SetPluginCanSave(bool can_save) override;
void PluginDidStartLoading() override;
@@ -148,12 +145,8 @@ class OutOfProcessInstance : public PdfViewPluginBase,
void UserMetricsRecordAction(const std::string& action) override;
private:
- void ResetRecentlySentFindUpdate(int32_t);
-
bool CanSaveEdits() const;
- void FormDidOpen(int32_t result);
-
// The Pepper image data that is in sync with mutable_image_data().
pp::ImageData pepper_image_data_;
@@ -165,13 +158,6 @@ class OutOfProcessInstance : public PdfViewPluginBase,
// http://crbug.com/132565
std::unique_ptr<pp::TextInput_Dev> text_input_;
- // Whether an update to the number of find results found was sent less than
- // `kFindResultCooldownMs` milliseconds ago.
- bool recently_sent_find_update_ = false;
-
- // The tickmarks.
- std::vector<pp::Rect> tickmarks_;
-
base::WeakPtrFactory<OutOfProcessInstance> weak_factory_{this};
};
diff --git a/chromium/pdf/pdf.h b/chromium/pdf/pdf.h
index 83e0be37ee6..66090764d1a 100644
--- a/chromium/pdf/pdf.h
+++ b/chromium/pdf/pdf.h
@@ -48,6 +48,9 @@ enum PrintingMode {
// Values 4 and 5 are similar to `kPostScript2` and `kPostScript3`, but are
// not intended for use in sandboxed environments like Chromium's.
kEmfWithReducedRasterization = 6,
+ kPostScript3WithType42Fonts = 7,
+ // Value 8 is similar to `kPostScript3WithType42Fonts`, but is not intended
+ // for use in sandboxed environments like Chromium's.
};
// `pdf_buffer` is the buffer that contains the entire PDF document to be
diff --git a/chromium/pdf/pdf_accessibility_action_handler.h b/chromium/pdf/pdf_accessibility_action_handler.h
index f065fffbb00..53e936148f8 100644
--- a/chromium/pdf/pdf_accessibility_action_handler.h
+++ b/chromium/pdf/pdf_accessibility_action_handler.h
@@ -13,6 +13,7 @@ class PdfAccessibilityActionHandler {
public:
virtual ~PdfAccessibilityActionHandler() = default;
+ virtual void EnableAccessibility() = 0;
virtual void HandleAccessibilityAction(
const AccessibilityActionData& action_data) = 0;
};
diff --git a/chromium/pdf/pdf_utils/dates.cc b/chromium/pdf/pdf_utils/dates.cc
index 6d2f9ba3343..51265b06a20 100644
--- a/chromium/pdf/pdf_utils/dates.cc
+++ b/chromium/pdf/pdf_utils/dates.cc
@@ -80,7 +80,7 @@ base::TimeDelta ParseOffset(DateDeserializer& deserializer) {
if (!sign.has_value() || (sign.value() != '+' && sign.value() != '-'))
return offset;
- offset += base::TimeDelta::FromHours(deserializer.PopDigits(2).value_or(0));
+ offset += base::Hours(deserializer.PopDigits(2).value_or(0));
// The spec requires that the hours offset be followed by an apostrophe, but
// don't be strict about its presence.
@@ -92,7 +92,7 @@ base::TimeDelta ParseOffset(DateDeserializer& deserializer) {
// following the minutes offset. One reason for the leniency is the apostrophe
// following the minues, which is only mentioned in earlier versions of the
// spec.
- offset += base::TimeDelta::FromMinutes(deserializer.PopDigits(2).value_or(0));
+ offset += base::Minutes(deserializer.PopDigits(2).value_or(0));
return sign.value() == '+' ? offset : -offset;
}
diff --git a/chromium/pdf/pdf_view_plugin_base.cc b/chromium/pdf/pdf_view_plugin_base.cc
index e795ae37e69..090ee1979ef 100644
--- a/chromium/pdf/pdf_view_plugin_base.cc
+++ b/chromium/pdf/pdf_view_plugin_base.cc
@@ -6,6 +6,7 @@
#include <algorithm>
#include <cmath>
+#include <iterator>
#include <memory>
#include <sstream>
#include <string>
@@ -22,8 +23,10 @@
#include "base/containers/span.h"
#include "base/cxx17_backports.h"
#include "base/feature_list.h"
+#include "base/i18n/rtl.h"
#include "base/i18n/time_formatting.h"
#include "base/location.h"
+#include "base/logging.h"
#include "base/memory/weak_ptr.h"
#include "base/metrics/histogram_functions.h"
#include "base/notreached.h"
@@ -43,8 +46,10 @@
#include "pdf/document_layout.h"
#include "pdf/document_metadata.h"
#include "pdf/paint_ready_rect.h"
+#include "pdf/pdf_engine.h"
#include "pdf/pdf_features.h"
#include "pdf/pdfium/pdfium_engine.h"
+#include "pdf/pdfium/pdfium_form_filler.h"
#include "pdf/ppapi_migration/image.h"
#include "pdf/ppapi_migration/result_codes.h"
#include "pdf/ppapi_migration/url_loader.h"
@@ -60,12 +65,14 @@
#include "third_party/skia/include/core/SkColor.h"
#include "ui/base/text/bytes_formatting.h"
#include "ui/events/blink/blink_event_util.h"
+#include "ui/gfx/geometry/point.h"
#include "ui/gfx/geometry/point_f.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/size.h"
+#include "ui/gfx/geometry/skia_conversions.h"
#include "ui/gfx/geometry/vector2d.h"
#include "ui/gfx/geometry/vector2d_f.h"
-#include "ui/gfx/skia_util.h"
+#include "url/gurl.h"
namespace chrome_pdf {
@@ -76,12 +83,12 @@ constexpr double kMinZoom = 0.01;
// A delay to wait between each accessibility page to keep the system
// responsive.
-constexpr base::TimeDelta kAccessibilityPageDelay =
- base::TimeDelta::FromMilliseconds(100);
+constexpr base::TimeDelta kAccessibilityPageDelay = base::Milliseconds(100);
+
+constexpr base::TimeDelta kFindResultCooldown = base::Milliseconds(100);
-constexpr char kChromePrintHost[] = "chrome://print/";
constexpr char kChromeExtensionHost[] =
- "chrome-extension://mhjfbmdgcfjbbpaeojofohoefgiehjai";
+ "chrome-extension://mhjfbmdgcfjbbpaeojofohoefgiehjai/";
// Same value as printing::COMPLETE_PREVIEW_DOCUMENT_INDEX.
constexpr int kCompletePDFIndex = -1;
@@ -112,12 +119,16 @@ base::Value PrepareReplyMessage(base::StringPiece reply_type,
return reply;
}
+bool IsPrintPreviewUrl(base::StringPiece url) {
+ return base::StartsWith(url, PdfViewPluginBase::kChromeUntrustedPrintHost);
+}
+
int ExtractPrintPreviewPageIndex(base::StringPiece src_url) {
- // Sample `src_url` format: chrome://print/id/page_index/print.pdf
+ // Sample `src_url` format: chrome-untrusted://print/id/page_index/print.pdf
// The page_index is zero-based, but can be negative with special meanings.
- std::vector<base::StringPiece> url_substr =
- base::SplitStringPiece(src_url.substr(strlen(kChromePrintHost)), "/",
- base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
+ std::vector<base::StringPiece> url_substr = base::SplitStringPiece(
+ src_url.substr(PdfViewPluginBase::kChromeUntrustedPrintHost.size()), "/",
+ base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
if (url_substr.size() != 3)
return kInvalidPDFIndex;
@@ -136,10 +147,58 @@ bool IsPreviewingPDF(int print_preview_page_count) {
} // namespace
+// static
+constexpr base::StringPiece PdfViewPluginBase::kChromePrintHost;
+
+// static
+constexpr base::StringPiece PdfViewPluginBase::kChromeUntrustedPrintHost;
+
PdfViewPluginBase::PdfViewPluginBase() = default;
PdfViewPluginBase::~PdfViewPluginBase() = default;
+void PdfViewPluginBase::InitializeBase(std::unique_ptr<PDFiumEngine> engine,
+ base::StringPiece embedder_origin,
+ base::StringPiece src_url,
+ base::StringPiece original_url,
+ bool full_frame,
+ SkColor background_color,
+ bool has_edits) {
+ // Check if the PDF is being loaded in the PDF chrome extension. We only allow
+ // the plugin to be loaded in the extension and print preview to avoid
+ // exposing sensitive APIs directly to external websites.
+ //
+ // This is enforced before launching the plugin process (see
+ // ChromeContentBrowserClient::ShouldAllowPluginCreation), so below we just do
+ // a CHECK as a defense-in-depth.
+ is_print_preview_ = (embedder_origin == kChromePrintHost);
+ CHECK(IsPrintPreview() || embedder_origin == kChromeExtensionHost);
+
+ full_frame_ = full_frame;
+ background_color_ = background_color;
+
+ DCHECK(engine);
+ engine_ = std::move(engine);
+
+ // 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
+ // it know the url to load. By not loading here we avoid loading the same
+ // document twice.
+ if (IsPrintPreview())
+ return;
+
+ LoadUrl(src_url, /*is_print_preview=*/false);
+ url_ = std::string(original_url);
+
+ // Not all edits go through the PDF plugin's form filler. The plugin instance
+ // can be restarted by exiting annotation mode on ChromeOS, which can set the
+ // document to an edited state.
+ edit_mode_ = has_edits;
+#if !BUILDFLAG(ENABLE_INK)
+ DCHECK(!edit_mode_);
+#endif // !BUILDFLAG(ENABLE_INK)
+}
+
void PdfViewPluginBase::ProposeDocumentLayout(const DocumentLayout& layout) {
base::Value message(base::Value::Type::DICTIONARY);
message.SetStringKey("type", "documentDimensions");
@@ -147,15 +206,8 @@ void PdfViewPluginBase::ProposeDocumentLayout(const DocumentLayout& layout) {
message.SetIntKey("height", layout.size().height());
message.SetKey("layoutOptions", layout.options().ToValue());
base::Value page_dimensions_list(base::Value::Type::LIST);
- for (size_t i = 0; i < layout.page_count(); ++i) {
- const gfx::Rect& page_rect = layout.page_rect(i);
- base::Value page_dimensions(base::Value::Type::DICTIONARY);
- page_dimensions.SetIntKey("x", page_rect.x());
- page_dimensions.SetIntKey("y", page_rect.y());
- page_dimensions.SetIntKey("width", page_rect.width());
- page_dimensions.SetIntKey("height", page_rect.height());
- page_dimensions_list.Append(std::move(page_dimensions));
- }
+ for (size_t i = 0; i < layout.page_count(); ++i)
+ page_dimensions_list.Append(base::Value(DictFromRect(layout.page_rect(i))));
message.SetKey("pageDimensions", std::move(page_dimensions_list));
SendMessage(std::move(message));
@@ -244,6 +296,40 @@ void PdfViewPluginBase::NavigateToDestination(int page,
SendMessage(std::move(message));
}
+void PdfViewPluginBase::UpdateTickMarks(
+ const std::vector<gfx::Rect>& tickmarks) {
+ float inverse_scale = 1.0f / device_scale_;
+ tickmarks_.clear();
+ tickmarks_.reserve(tickmarks.size());
+ std::transform(tickmarks.begin(), tickmarks.end(),
+ std::back_inserter(tickmarks_),
+ [inverse_scale](const gfx::Rect& t) -> gfx::Rect {
+ return gfx::ScaleToEnclosingRect(t, inverse_scale);
+ });
+}
+
+void PdfViewPluginBase::NotifyNumberOfFindResultsChanged(int total,
+ bool final_result) {
+ // We don't want to spam the renderer with too many updates to the number of
+ // find results. Don't send an update if we sent one too recently. If it's the
+ // final update, we always send it though.
+ if (recently_sent_find_update_ && !final_result)
+ return;
+
+ NotifyFindResultsChanged(total, final_result);
+ NotifyFindTickmarks(tickmarks_);
+
+ if (final_result)
+ return;
+
+ recently_sent_find_update_ = true;
+ ScheduleTaskOnMainThread(
+ FROM_HERE,
+ base::BindOnce(&PdfViewPluginBase::ResetRecentlySentFindUpdate,
+ GetWeakPtr()),
+ /*result=*/0, kFindResultCooldown);
+}
+
void PdfViewPluginBase::NotifyTouchSelectionOccurred() {
base::Value message(base::Value::Type::DICTIONARY);
message.SetStringKey("type", "touchSelectionOccurred");
@@ -298,6 +384,24 @@ void PdfViewPluginBase::Print() {
InvokePrintDialog();
}
+void PdfViewPluginBase::SubmitForm(const std::string& url,
+ const void* data,
+ int length) {
+ // `url` might be a relative URL. Resolve it against the document's URL.
+ GURL resolved_url = GURL(GetURL()).Resolve(url);
+ if (!resolved_url.is_valid())
+ return;
+
+ UrlRequest request;
+ request.url = resolved_url.spec();
+ request.method = "POST";
+ request.body.assign(static_cast<const char*>(data), length);
+
+ form_loader_ = CreateUrlLoaderInternal();
+ form_loader_->Open(
+ request, base::BindOnce(&PdfViewPluginBase::DidFormOpen, GetWeakPtr()));
+}
+
std::unique_ptr<UrlLoader> PdfViewPluginBase::CreateUrlLoader() {
if (full_frame_) {
DidStartLoading();
@@ -327,7 +431,6 @@ void PdfViewPluginBase::DocumentLoadComplete() {
SendAttachments();
SendBookmarks();
SendMetadata();
- SendLoadingProgress(/*percentage=*/100);
if (accessibility_state_ == AccessibilityState::kPending)
LoadAccessibility();
@@ -390,7 +493,6 @@ void PdfViewPluginBase::DocumentLoadProgress(uint32_t available,
if (progress <= last_progress_sent_ + 1)
return;
- last_progress_sent_ = progress;
SendLoadingProgress(progress);
}
@@ -568,6 +670,7 @@ void PdfViewPluginBase::ConsumeSaveToken(const std::string& token) {
void PdfViewPluginBase::SendLoadingProgress(double percentage) {
DCHECK(percentage == -1 || (percentage >= 0 && percentage <= 100));
+ last_progress_sent_ = percentage;
base::Value message(base::Value::Type::DICTIONARY);
message.SetStringKey("type", "loadProgress");
@@ -663,11 +766,18 @@ bool PdfViewPluginBase::UnsupportedFeatureIsReportedForTesting(
return base::Contains(unsupported_features_reported_, feature);
}
-void PdfViewPluginBase::InitializeEngine(std::unique_ptr<PDFiumEngine> engine) {
+void PdfViewPluginBase::InitializeEngineForTesting(
+ std::unique_ptr<PDFiumEngine> engine) {
DCHECK(engine);
engine_ = std::move(engine);
}
+std::unique_ptr<PDFiumEngine> PdfViewPluginBase::CreateEngine(
+ PDFEngine::Client* client,
+ PDFiumFormFiller::ScriptOption script_option) {
+ return std::make_unique<PDFiumEngine>(client, script_option);
+}
+
void PdfViewPluginBase::DestroyEngine() {
engine_.reset();
}
@@ -676,14 +786,13 @@ void PdfViewPluginBase::DestroyPreviewEngine() {
preview_engine_.reset();
}
-void PdfViewPluginBase::ValidateDocumentUrl(base::StringPiece document_url) {
- CHECK(base::StartsWith(document_url, kChromeExtensionHost) ||
- IsPrintPreview());
-}
+void PdfViewPluginBase::LoadUrl(base::StringPiece url, bool is_print_preview) {
+ // `last_progress_sent_` should only be reset for the primary load.
+ if (!is_print_preview)
+ last_progress_sent_ = 0;
-void PdfViewPluginBase::LoadUrl(const std::string& url, bool is_print_preview) {
UrlRequest request;
- request.url = url;
+ request.url = RewriteRequestUrl(url);
request.method = "GET";
request.ignore_redirects = true;
@@ -696,6 +805,10 @@ void PdfViewPluginBase::LoadUrl(const std::string& url, bool is_print_preview) {
GetWeakPtr(), std::move(loader)));
}
+std::string PdfViewPluginBase::RewriteRequestUrl(base::StringPiece url) const {
+ return std::string(url);
+}
+
void PdfViewPluginBase::InvalidateAfterPaintDone() {
if (deferred_invalidates_.empty())
return;
@@ -758,12 +871,10 @@ void PdfViewPluginBase::PrintEnd() {
engine_->PrintEnd();
}
-void PdfViewPluginBase::UpdateGeometryOnViewChanged(
- const gfx::Rect& new_view_rect,
+void PdfViewPluginBase::UpdateGeometryOnPluginRectChanged(
+ const gfx::Rect& new_plugin_rect,
float new_device_scale) {
DCHECK_GT(new_device_scale, 0.0f);
- const gfx::Rect new_plugin_rect =
- gfx::ScaleToEnclosingRectSafe(new_view_rect, new_device_scale);
if (new_device_scale == device_scale_ && new_plugin_rect == plugin_rect_)
return;
@@ -771,7 +882,13 @@ void PdfViewPluginBase::UpdateGeometryOnViewChanged(
const float old_device_scale = device_scale_;
device_scale_ = new_device_scale;
plugin_rect_ = new_plugin_rect;
- plugin_dip_size_ = new_view_rect.size();
+ // TODO(crbug.com/1250173): For the Pepper-free plugin, `plugin_dip_size_` is
+ // calculated from the `window_rect` in PdfViewWebPlugin::UpdateGeometry().
+ // We should try to avoid the downscaling during this calculation process and
+ // maybe migrate off `plugin_dip_size_`.
+ plugin_dip_size_ =
+ gfx::ScaleToEnclosingRectSafe(new_plugin_rect, 1.0f / new_device_scale)
+ .size();
paint_manager_.SetSize(plugin_rect_.size(), device_scale_);
@@ -850,26 +967,31 @@ void PdfViewPluginBase::CalculateBackgroundParts() {
background_parts_.push_back(part);
}
-void PdfViewPluginBase::UpdateScroll() {
- DCHECK(!stop_scrolling_);
- const gfx::PointF scaled_scroll_position = gfx::ScalePoint(
- BoundScrollPositionToDocument(gfx::PointF(scroll_position_)),
- device_scale_);
- engine()->ScrolledToXPosition(scaled_scroll_position.x());
- engine()->ScrolledToYPosition(scaled_scroll_position.y());
-}
+void PdfViewPluginBase::UpdateScroll(const gfx::Vector2dF& scroll_offset) {
+ if (stop_scrolling_)
+ return;
-gfx::PointF PdfViewPluginBase::BoundScrollPositionToDocument(
- const gfx::PointF& scroll_position) {
float max_x = std::max(document_size_.width() * static_cast<float>(zoom_) -
plugin_dip_size_.width(),
0.0f);
- float x = base::clamp(scroll_position.x(), 0.0f, max_x);
float max_y = std::max(document_size_.height() * static_cast<float>(zoom_) -
plugin_dip_size_.height(),
0.0f);
- float y = base::clamp(scroll_position.y(), 0.0f, max_y);
- return gfx::PointF(x, y);
+
+ // TODO(crbug.com/1256965): Right-to-left scrolling currently is not
+ // compatible with the PDF viewer's "scroller" element.
+ gfx::PointF scroll_position;
+ if (ui_direction_ == base::i18n::RIGHT_TO_LEFT && IsPrintPreview())
+ scroll_position.set_x(max_x);
+ scroll_position += scroll_offset;
+
+ gfx::PointF scaled_scroll_position(
+ base::clamp(scroll_position.x(), 0.0f, max_x),
+ base::clamp(scroll_position.y(), 0.0f, max_y));
+ scaled_scroll_position.Scale(device_scale_);
+
+ engine()->ScrolledToXPosition(scaled_scroll_position.x());
+ engine()->ScrolledToYPosition(scaled_scroll_position.y());
}
int PdfViewPluginBase::GetDocumentPixelWidth() const {
@@ -926,6 +1048,22 @@ void PdfViewPluginBase::PrepareAndSetAccessibilityViewportInfo() {
SetAccessibilityViewportInfo(viewport_info);
}
+bool PdfViewPluginBase::StartFind(const std::string& text,
+ bool case_sensitive) {
+ engine_->StartFind(text, case_sensitive);
+ return true;
+}
+
+void PdfViewPluginBase::SelectFindResult(bool forward) {
+ engine_->SelectFindResult(forward);
+}
+
+void PdfViewPluginBase::StopFind() {
+ engine_->StopFind();
+ tickmarks_.clear();
+ NotifyFindTickmarks(tickmarks_);
+}
+
void PdfViewPluginBase::SetZoom(double scale) {
double old_zoom = zoom_;
zoom_ = scale;
@@ -933,8 +1071,14 @@ void PdfViewPluginBase::SetZoom(double scale) {
}
// static
-bool PdfViewPluginBase::IsPrintPreviewUrl(base::StringPiece url) {
- return base::StartsWith(url, kChromePrintHost);
+base::Value::DictStorage PdfViewPluginBase::DictFromRect(
+ const gfx::Rect& rect) {
+ base::Value::DictStorage dict;
+ dict["x"] = base::Value(rect.x());
+ dict["y"] = base::Value(rect.y());
+ dict["width"] = base::Value(rect.width());
+ dict["height"] = base::Value(rect.height());
+ return dict;
}
void PdfViewPluginBase::HandleDisplayAnnotationsMessage(
@@ -1041,8 +1185,13 @@ void PdfViewPluginBase::HandleResetPrintPreviewModeMessage(
document_load_state_ = DocumentLoadState::kLoading;
LoadUrl(GetURL(), /*is_print_preview=*/false);
preview_engine_.reset();
- InitializeEngine(std::make_unique<PDFiumEngine>(
- this, PDFiumFormFiller::ScriptOption::kNoJavaScript));
+
+ // TODO(crbug.com/1237952): Figure out a more consistent way to preserve
+ // engine settings across a Print Preview reset.
+ engine_ = CreateEngine(this, PDFiumFormFiller::ScriptOption::kNoJavaScript);
+ engine()->ZoomUpdated(zoom_ * device_scale_);
+ engine()->PageOffsetUpdated(available_area_.OffsetFromOrigin());
+ engine()->PluginSizeUpdated(available_area_.size());
engine()->SetGrayscale(is_grayscale);
paint_manager_.InvalidateRect(gfx::Rect(plugin_rect().size()));
@@ -1112,9 +1261,8 @@ void PdfViewPluginBase::HandleSelectAllMessage(const base::Value& /*message*/) {
void PdfViewPluginBase::HandleSetBackgroundColorMessage(
const base::Value& message) {
- const SkColor background_color =
+ background_color_ =
base::checked_cast<SkColor>(message.FindDoubleKey("color").value());
- SetBackgroundColor(background_color);
}
void PdfViewPluginBase::HandleSetReadOnlyMessage(const base::Value& message) {
@@ -1131,13 +1279,8 @@ void PdfViewPluginBase::HandleStopScrollingMessage(
}
void PdfViewPluginBase::HandleUpdateScrollMessage(const base::Value& message) {
- if (stop_scrolling_)
- return;
-
- scroll_position_ =
- gfx::Point(base::checked_cast<int>(message.FindDoubleKey("x").value()),
- base::checked_cast<int>(message.FindDoubleKey("y").value()));
- UpdateScroll();
+ UpdateScroll(gfx::Vector2dF(message.FindDoubleKey("x").value(),
+ message.FindDoubleKey("y").value()));
}
void PdfViewPluginBase::HandleViewportMessage(const base::Value& message) {
@@ -1146,13 +1289,22 @@ void PdfViewPluginBase::HandleViewportMessage(const base::Value& message) {
if (layout_options_value) {
DocumentLayout::Options layout_options;
layout_options.FromValue(*layout_options_value);
+
+ ui_direction_ = layout_options.direction();
+
// TODO(crbug.com/1013800): Eliminate need to get document size from here.
document_size_ = engine()->ApplyDocumentLayout(layout_options);
OnGeometryChanged(zoom_, device_scale_);
+
+ // Send 100% loading progress only after initial layout negotiated.
+ if (last_progress_sent_ < 100 &&
+ document_load_state_ == DocumentLoadState::kComplete) {
+ SendLoadingProgress(/*percentage=*/100);
+ }
}
- gfx::PointF scroll_position(message.FindDoubleKey("xOffset").value(),
- message.FindDoubleKey("yOffset").value());
+ gfx::Vector2dF scroll_offset(message.FindDoubleKey("xOffset").value(),
+ message.FindDoubleKey("yOffset").value());
double new_zoom = message.FindDoubleKey("zoom").value();
const PinchPhase pinch_phase =
static_cast<PinchPhase>(message.FindIntKey("pinchPhase").value());
@@ -1162,7 +1314,7 @@ void PdfViewPluginBase::HandleViewportMessage(const base::Value& message) {
const double zoom_ratio = new_zoom / zoom_;
if (pinch_phase == PinchPhase::kStart) {
- scroll_position_at_last_raster_ = scroll_position;
+ scroll_offset_at_last_raster_ = scroll_offset;
last_bitmap_smaller_ = false;
needs_reraster_ = false;
return;
@@ -1198,9 +1350,9 @@ void PdfViewPluginBase::HandleViewportMessage(const base::Value& message) {
// We want to keep the paint in the middle but it must stay in the same
// position relative to the scroll bars.
paint_offset = gfx::Vector2d(0, (1 - zoom_ratio) * pinch_center.y());
- scroll_delta =
- gfx::Vector2d(0, (scroll_position.y() -
- scroll_position_at_last_raster_.y() * zoom_ratio));
+ scroll_delta = gfx::Vector2d(
+ 0,
+ (scroll_offset.y() - scroll_offset_at_last_raster_.y() * zoom_ratio));
pinch_vector = gfx::Vector2d();
last_bitmap_smaller_ = true;
@@ -1215,11 +1367,9 @@ void PdfViewPluginBase::HandleViewportMessage(const base::Value& message) {
(1 - new_zoom / zoom_when_doc_covers_plugin_width) * pinch_center.x(),
(1 - zoom_ratio) * pinch_center.y());
pinch_vector = gfx::Vector2d();
- scroll_delta =
- gfx::Vector2d((scroll_position.x() -
- scroll_position_at_last_raster_.x() * zoom_ratio),
- (scroll_position.y() -
- scroll_position_at_last_raster_.y() * zoom_ratio));
+ scroll_delta = gfx::Vector2d(
+ (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,
@@ -1240,9 +1390,9 @@ void PdfViewPluginBase::HandleViewportMessage(const base::Value& message) {
needs_reraster_ = true;
// If we're rerastering due to zooming out, we need to update the scroll
- // position for the last raster, in case the user continues the gesture by
+ // offset for the last raster, in case the user continues the gesture by
// zooming in.
- scroll_position_at_last_raster_ = scroll_position;
+ scroll_offset_at_last_raster_ = scroll_offset;
}
// Bound the input parameters.
@@ -1250,9 +1400,7 @@ void PdfViewPluginBase::HandleViewportMessage(const base::Value& message) {
DCHECK(message.FindBoolKey("userInitiated").has_value());
SetZoom(new_zoom);
- scroll_position = BoundScrollPositionToDocument(scroll_position);
- engine()->ScrolledToXPosition(scroll_position.x() * device_scale_);
- engine()->ScrolledToYPosition(scroll_position.y() * device_scale_);
+ UpdateScroll(scroll_offset);
}
void PdfViewPluginBase::DidStartLoading() {
@@ -1496,6 +1644,11 @@ void PdfViewPluginBase::LoadAccessibility() {
/*result=*/0, kAccessibilityPageDelay);
}
+void PdfViewPluginBase::ResetRecentlySentFindUpdate(
+ int32_t /*unused_but_required*/) {
+ recently_sent_find_update_ = false;
+}
+
namespace {
// These values are persisted to logs. Entries should not be renumbered and
@@ -1547,16 +1700,34 @@ void PdfViewPluginBase::HistogramCustomCounts(const char* name,
base::UmaHistogramCustomCounts(name, sample, min, max, bucket_count);
}
+void PdfViewPluginBase::DidOpen(std::unique_ptr<UrlLoader> loader,
+ int32_t result) {
+ if (result == kSuccess) {
+ if (!engine()->HandleDocumentLoad(std::move(loader), GetURL())) {
+ document_load_state_ = DocumentLoadState::kLoading;
+ DocumentLoadFailed();
+ }
+ } else if (result != kErrorAborted) {
+ DocumentLoadFailed();
+ }
+}
+
void PdfViewPluginBase::DidOpenPreview(std::unique_ptr<UrlLoader> loader,
int32_t result) {
- DCHECK_EQ(result, Result::kSuccess);
+ DCHECK_EQ(result, kSuccess);
preview_client_ = std::make_unique<PreviewModeClient>(this);
- preview_engine_ = std::make_unique<PDFiumEngine>(
- preview_client_.get(), PDFiumFormFiller::ScriptOption::kNoJavaScript);
+ preview_engine_ = CreateEngine(preview_client_.get(),
+ PDFiumFormFiller::ScriptOption::kNoJavaScript);
preview_engine_->PluginSizeUpdated({});
preview_engine_->HandleDocumentLoad(std::move(loader), GetURL());
}
+void PdfViewPluginBase::DidFormOpen(int32_t result) {
+ // TODO(crbug.com/719344): Process response.
+ LOG_IF(ERROR, result != kSuccess) << "DidFormOpen failed: " << result;
+ form_loader_.reset();
+}
+
void PdfViewPluginBase::OnPrintPreviewLoaded() {
// Scroll location is retained across document loads in print preview mode, so
// there's no need to override the scroll position by scrolling again.
@@ -1596,7 +1767,7 @@ void PdfViewPluginBase::ProcessPreviewPageInfo(const std::string& url,
void PdfViewPluginBase::LoadAvailablePreviewPage() {
if (preview_pages_info_.empty() ||
- document_load_state() != DocumentLoadState::kComplete ||
+ document_load_state_ != DocumentLoadState::kComplete ||
preview_document_load_state_ == DocumentLoadState::kLoading) {
return;
}
diff --git a/chromium/pdf/pdf_view_plugin_base.h b/chromium/pdf/pdf_view_plugin_base.h
index b2e1662cb1c..6e3cebde7e9 100644
--- a/chromium/pdf/pdf_view_plugin_base.h
+++ b/chromium/pdf/pdf_view_plugin_base.h
@@ -15,7 +15,10 @@
#include "base/callback.h"
#include "base/containers/flat_set.h"
#include "base/containers/queue.h"
+#include "base/i18n/rtl.h"
#include "base/memory/weak_ptr.h"
+#include "base/strings/string_piece.h"
+#include "base/values.h"
#include "pdf/accessibility_structs.h"
#include "pdf/paint_manager.h"
#include "pdf/pdf_engine.h"
@@ -26,19 +29,18 @@
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/base/cursor/mojom/cursor_type.mojom-shared.h"
-#include "ui/gfx/geometry/point.h"
-#include "ui/gfx/geometry/point_f.h"
#include "ui/gfx/geometry/rect.h"
-
-namespace base {
-class Value;
-} // namespace base
+#include "ui/gfx/geometry/vector2d_f.h"
namespace blink {
class WebInputEvent;
struct WebPrintPresetOptions;
} // namespace blink
+namespace gfx {
+class PointF;
+} // namespace gfx
+
namespace chrome_pdf {
class Image;
@@ -65,6 +67,13 @@ class PdfViewPluginBase : public PDFEngine::Client,
// and is also enforced in chrome/browser/resources/pdf/pdf_viewer.js.
static constexpr size_t kMaximumSavedFileSize = 100 * 1000 * 1000;
+ // Print Preview base URL.
+ static constexpr base::StringPiece kChromePrintHost = "chrome://print/";
+
+ // Untrusted Print Preview base URL.
+ static constexpr base::StringPiece kChromeUntrustedPrintHost =
+ "chrome-untrusted://print/";
+
enum class AccessibilityState {
kOff = 0, // Off.
kPending, // Enabled but waiting for doc to load.
@@ -101,6 +110,8 @@ class PdfViewPluginBase : public PDFEngine::Client,
const float* x,
const float* y,
const float* zoom) override;
+ void UpdateTickMarks(const std::vector<gfx::Rect>& tickmarks) override;
+ void NotifyNumberOfFindResultsChanged(int total, bool final_result) override;
void NotifyTouchSelectionOccurred() override;
void GetDocumentPassword(
base::OnceCallback<void(const std::string&)> callback) override;
@@ -112,6 +123,9 @@ class PdfViewPluginBase : public PDFEngine::Client,
const std::string& subject,
const std::string& body) override;
void Print() override;
+ void SubmitForm(const std::string& url,
+ const void* data,
+ int length) override;
std::unique_ptr<UrlLoader> CreateUrlLoader() override;
void DocumentLoadComplete() override;
void DocumentLoadFailed() override;
@@ -157,6 +171,16 @@ class PdfViewPluginBase : public PDFEngine::Client,
return notified_browser_about_unsupported_feature_;
}
+ void InitializeEngineForTesting(std::unique_ptr<PDFiumEngine> engine);
+
+ void set_full_frame_for_testing(bool full_frame) { full_frame_ = full_frame; }
+
+ DocumentLoadState document_load_state_for_testing() const {
+ return document_load_state_;
+ }
+
+ bool edit_mode_for_testing() const { return edit_mode_; }
+
protected:
struct BackgroundPart {
gfx::Rect location;
@@ -166,9 +190,22 @@ class PdfViewPluginBase : public PDFEngine::Client,
PdfViewPluginBase();
~PdfViewPluginBase() override;
- // Initializes the main `PDFiumEngine` with `engine`. Any existing engine will
- // be replaced. `engine` must not be nullptr.
- void InitializeEngine(std::unique_ptr<PDFiumEngine> engine);
+ // Performs initialization common to all implementations of this plugin.
+ // `engine` should be an appropriately-configured PDF engine, and
+ // `embedder_origin` should be the origin of the plugin's embedder. The other
+ // parameters come from the corresponding plugin attributes.
+ void InitializeBase(std::unique_ptr<PDFiumEngine> engine,
+ base::StringPiece embedder_origin,
+ base::StringPiece src_url,
+ base::StringPiece original_url,
+ bool full_frame,
+ SkColor background_color,
+ bool has_edits);
+
+ // Creates a new `PDFiumEngine`.
+ virtual std::unique_ptr<PDFiumEngine> CreateEngine(
+ PDFEngine::Client* client,
+ PDFiumFormFiller::ScriptOption script_option);
// Destroys the main `PDFiumEngine`. Subclasses should call this method in
// their destructor to ensure the engine is destroyed first.
@@ -181,11 +218,9 @@ class PdfViewPluginBase : public PDFEngine::Client,
const PDFiumEngine* engine() const { return engine_.get(); }
PDFiumEngine* engine() { return engine_.get(); }
- void ValidateDocumentUrl(base::StringPiece document_url);
-
// Starts loading `url`. If `is_print_preview` is `true`, load for print
// preview instead of normal PDF viewing.
- void LoadUrl(const std::string& url, bool is_print_preview);
+ void LoadUrl(base::StringPiece url, bool is_print_preview);
// Gets a weak pointer with a lifetime matching the derived class.
virtual base::WeakPtr<PdfViewPluginBase> GetWeakPtr() = 0;
@@ -194,8 +229,11 @@ class PdfViewPluginBase : public PDFEngine::Client,
// frame's origin.
virtual std::unique_ptr<UrlLoader> CreateUrlLoaderInternal() = 0;
- // Handles `LoadUrl()` result.
- virtual void DidOpen(std::unique_ptr<UrlLoader> loader, int32_t result) = 0;
+ // Rewrites the request URL just before sending to the URL loader.
+ //
+ // TODO(crbug.com/1238829): This is a workaround for Pepper not supporting
+ // chrome-untrusted://print/ URLs.
+ virtual std::string RewriteRequestUrl(base::StringPiece url) const;
bool HandleInputEvent(const blink::WebInputEvent& event);
@@ -235,11 +273,11 @@ class PdfViewPluginBase : public PDFEngine::Client,
// Returns the plugin-specific image data buffer.
virtual Image GetPluginImageData() const;
- // Updates the geometry of the plugin and its image data if the view's
- // size or scale has changed. `new_view_rect` must be in CSS pixels (without
- // device scale applied).
- void UpdateGeometryOnViewChanged(const gfx::Rect& new_view_rect,
- float new_device_scale);
+ // Updates the geometry of the plugin and its image data if the plugin rect
+ // or the device scale has changed. `new_plugin_rect` must be in device
+ // pixels (with the device scale applied).
+ void UpdateGeometryOnPluginRectChanged(const gfx::Rect& new_plugin_rect,
+ float new_device_scale);
// A helper of OnGeometryChanged() which updates the available area and
// the background parts, and notifies the PDF engine of geometry changes.
@@ -249,11 +287,9 @@ class PdfViewPluginBase : public PDFEngine::Client,
// aren't painted by the PDF engine).
void CalculateBackgroundParts();
- // Repaints the plugin contents based on the current scroll position.
- void UpdateScroll();
-
- // Bound the given scroll position to the document.
- gfx::PointF BoundScrollPositionToDocument(const gfx::PointF& scroll_position);
+ // Updates the scroll position. `scroll_offset` is in CSS pixels relative to
+ // the scroll origin (which depends on the UI direction).
+ void UpdateScroll(const gfx::Vector2dF& scroll_offset);
// Computes document width/height in device pixels, based on current zoom and
// device scale
@@ -289,6 +325,17 @@ class PdfViewPluginBase : public PDFEngine::Client,
virtual void SetAccessibilityViewportInfo(
const AccessibilityViewportInfo& viewport_info) = 0;
+ // Find handlers.
+ bool StartFind(const std::string& text, bool case_sensitive);
+ void SelectFindResult(bool forward);
+ void StopFind();
+
+ // Notify the plugin container about the total matches for a find request.
+ virtual void NotifyFindResultsChanged(int total, bool final_result) = 0;
+
+ // Notify the frame about the tickmarks for the find request.
+ virtual void NotifyFindTickmarks(const std::vector<gfx::Rect>& tickmarks) = 0;
+
// Returns the print preset options for the document.
blink::WebPrintPresetOptions GetPrintPresetOptions();
@@ -342,8 +389,6 @@ class PdfViewPluginBase : public PDFEngine::Client,
// Records user actions.
virtual void UserMetricsRecordAction(const std::string& action) = 0;
- void set_url(const std::string& url) { url_ = url; }
-
ui::mojom::CursorType cursor_type() const { return cursor_type_; }
void set_cursor_type(ui::mojom::CursorType cursor_type) {
cursor_type_ = cursor_type;
@@ -352,7 +397,6 @@ class PdfViewPluginBase : public PDFEngine::Client,
const std::string& link_under_cursor() const { return link_under_cursor_; }
bool full_frame() const { return full_frame_; }
- void set_full_frame(bool full_frame) { full_frame_ = full_frame; }
SkBitmap& mutable_image_data() { return image_data_; }
@@ -362,10 +406,6 @@ class PdfViewPluginBase : public PDFEngine::Client,
const gfx::Rect& plugin_rect() const { return plugin_rect_; }
- void SetBackgroundColor(SkColor background_color) {
- background_color_ = background_color;
- }
-
// Sets the new zoom scale.
void SetZoom(double scale);
@@ -373,34 +413,16 @@ class PdfViewPluginBase : public PDFEngine::Client,
float device_scale() const { return device_scale_; }
- void set_scroll_position(const gfx::Point& scroll_position) {
- scroll_position_ = scroll_position;
- }
-
- bool stop_scrolling() const { return stop_scrolling_; }
-
- DocumentLoadState document_load_state() const { return document_load_state_; }
- void set_document_load_state(DocumentLoadState state) {
- document_load_state_ = state;
- }
-
AccessibilityState accessibility_state() const {
return accessibility_state_;
}
- bool edit_mode() const { return edit_mode_; }
- void set_edit_mode(bool edit_mode) { edit_mode_ = edit_mode; }
-
- void set_is_print_preview(bool is_print_preview) {
- is_print_preview_ = is_print_preview;
- }
-
- static bool IsPrintPreviewUrl(base::StringPiece url);
-
static constexpr bool IsSaveDataSizeValid(size_t size) {
return size > 0 && size <= kMaximumSavedFileSize;
}
+ static base::Value::DictStorage DictFromRect(const gfx::Rect& rect);
+
private:
// Message handlers.
void HandleDisplayAnnotationsMessage(const base::Value& message);
@@ -459,6 +481,8 @@ class PdfViewPluginBase : public PDFEngine::Client,
// Starts loading accessibility information.
void LoadAccessibility();
+ void ResetRecentlySentFindUpdate(int32_t /*unused_but_required*/);
+
// Records metrics about the document metadata.
void RecordDocumentMetrics();
@@ -475,9 +499,15 @@ class PdfViewPluginBase : public PDFEngine::Client,
int32_t max,
uint32_t bucket_count);
+ // Handles `LoadUrl()` result.
+ void DidOpen(std::unique_ptr<UrlLoader> loader, int32_t result);
+
// Handles `LoadUrl()` result for print preview.
void DidOpenPreview(std::unique_ptr<UrlLoader> loader, int32_t result);
+ // Handles `Open()` result for `form_loader_`.
+ void DidFormOpen(int32_t result);
+
// Performs tasks necessary when the document is loaded in print preview mode.
void OnPrintPreviewLoaded();
@@ -487,7 +517,7 @@ class PdfViewPluginBase : public PDFEngine::Client,
// Process the preview page data information. `src_url` specifies the preview
// page data location. The `src_url` is in the format:
- // chrome://print/id/page_number/print.pdf
+ // chrome-untrusted://print/id/page_number/print.pdf
// `dest_page_index` specifies the blank page index that needs to be replaced
// with the new page data.
void ProcessPreviewPageInfo(const std::string& src_url, int dest_page_index);
@@ -557,12 +587,12 @@ class PdfViewPluginBase : public PDFEngine::Client,
// True if we request a new bitmap rendering.
bool needs_reraster_ = true;
- // The scroll position in CSS pixels.
- gfx::Point scroll_position_;
+ // The UI direction.
+ base::i18n::TextDirection ui_direction_ = base::i18n::UNKNOWN_DIRECTION;
- // The scroll position for the last raster, before any transformations are
- // applied.
- gfx::PointF scroll_position_at_last_raster_;
+ // The scroll offset for the last raster in CSS pixels, before any
+ // transformations are applied.
+ gfx::Vector2dF scroll_offset_at_last_raster_;
// If this is true, then don't scroll the plugin in response to the messages
// from DidChangeView() or HandleUpdateScrollMessage(). This will be true when
@@ -595,6 +625,13 @@ class PdfViewPluginBase : public PDFEngine::Client,
// reconstructing the tree for new document layouts.
int32_t next_accessibility_page_index_ = 0;
+ // Whether an update to the number of find results found was sent less than
+ // `kFindResultCooldownMs` milliseconds ago.
+ bool recently_sent_find_update_ = false;
+
+ // Stores the tickmarks to be shown for the current find results.
+ std::vector<gfx::Rect> tickmarks_;
+
// Keeps track of which unsupported features have been reported to avoid
// spamming the metrics if a feature shows up many times per document.
base::flat_set<std::string> unsupported_features_reported_;
@@ -606,6 +643,9 @@ class PdfViewPluginBase : public PDFEngine::Client,
// Whether the document is in edit mode.
bool edit_mode_ = false;
+ // Used for submitting forms.
+ std::unique_ptr<UrlLoader> form_loader_;
+
// Assigned a value only between `PrintBegin()` and `PrintEnd()` calls.
absl::optional<blink::WebPrintParams> print_params_;
diff --git a/chromium/pdf/pdf_view_plugin_base_unittest.cc b/chromium/pdf/pdf_view_plugin_base_unittest.cc
index e1f7219d303..d1ab7153485 100644
--- a/chromium/pdf/pdf_view_plugin_base_unittest.cc
+++ b/chromium/pdf/pdf_view_plugin_base_unittest.cc
@@ -10,21 +10,25 @@
#include <vector>
#include "base/containers/contains.h"
-#include "base/containers/flat_set.h"
+#include "base/cxx17_backports.h"
#include "base/memory/weak_ptr.h"
+#include "base/strings/string_piece.h"
#include "base/test/icu_test_util.h"
+#include "base/test/values_test_util.h"
#include "base/time/time.h"
#include "base/values.h"
#include "pdf/accessibility_structs.h"
#include "pdf/buildflags.h"
#include "pdf/content_restriction.h"
#include "pdf/document_attachment_info.h"
+#include "pdf/document_layout.h"
#include "pdf/document_metadata.h"
#include "pdf/pdf_engine.h"
-#include "pdf/pdfium/pdfium_engine.h"
+#include "pdf/pdfium/pdfium_form_filler.h"
#include "pdf/ppapi_migration/callback.h"
#include "pdf/ppapi_migration/graphics.h"
#include "pdf/ppapi_migration/url_loader.h"
+#include "pdf/test/test_pdfium_engine.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
@@ -35,83 +39,17 @@ namespace chrome_pdf {
namespace {
+using ::testing::ByMove;
+using ::testing::ElementsAre;
+using ::testing::IsEmpty;
+using ::testing::Return;
+using ::testing::SaveArg;
+using ::testing::StrEq;
+
// Keep it in-sync with the `kFinalFallbackName` returned by
// net::GetSuggestedFilename().
constexpr char kDefaultDownloadFileName[] = "download";
-// Dummy data to save.
-constexpr uint8_t kSaveData[] = {'1', '2', '3'};
-
-// Page number.
-constexpr uint32_t kPageNumber = 13u;
-
-class TestPDFiumEngine : public PDFiumEngine {
- public:
- explicit TestPDFiumEngine(PDFEngine::Client* client)
- : PDFiumEngine(client, PDFiumFormFiller::ScriptOption::kNoJavaScript) {}
-
- TestPDFiumEngine(const TestPDFiumEngine&) = delete;
-
- TestPDFiumEngine& operator=(const TestPDFiumEngine&) = delete;
-
- ~TestPDFiumEngine() override = default;
-
- bool HasPermission(DocumentPermission permission) const override {
- return base::Contains(permissions_, permission);
- }
-
- const std::vector<DocumentAttachmentInfo>& GetDocumentAttachmentInfoList()
- const override {
- return doc_attachment_info_list_;
- }
-
- const DocumentMetadata& GetDocumentMetadata() const override {
- return metadata_;
- }
-
- int GetNumberOfPages() const override {
- return static_cast<int>(kPageNumber);
- }
-
- base::Value GetBookmarks() override {
- // Return an empty bookmark list.
- return base::Value(base::Value::Type::LIST);
- }
-
- uint32_t GetLoadedByteSize() override { return sizeof(kSaveData); }
-
- bool ReadLoadedBytes(uint32_t length, void* buffer) override {
- DCHECK_LE(length, GetLoadedByteSize());
- memcpy(buffer, kSaveData, length);
- return true;
- }
-
- std::vector<uint8_t> GetSaveData() override {
- return std::vector<uint8_t>(std::begin(kSaveData), std::end(kSaveData));
- }
-
- void SetPermissions(const std::vector<DocumentPermission>& permissions) {
- permissions_.clear();
-
- for (auto& permission : permissions)
- permissions_.insert(permission);
- }
-
- protected:
- std::vector<DocumentAttachmentInfo>& doc_attachment_info_list() {
- return doc_attachment_info_list_;
- }
-
- DocumentMetadata& metadata() { return metadata_; }
-
- private:
- std::vector<DocumentAttachmentInfo> doc_attachment_info_list_;
-
- DocumentMetadata metadata_;
-
- base::flat_set<DocumentPermission> permissions_;
-};
-
class TestPDFiumEngineWithDocInfo : public TestPDFiumEngine {
public:
explicit TestPDFiumEngineWithDocInfo(PDFEngine::Client* client)
@@ -203,14 +141,15 @@ class FakePdfViewPluginBase : public PdfViewPluginBase {
public:
// Public for testing.
using PdfViewPluginBase::accessibility_state;
- using PdfViewPluginBase::document_load_state;
- using PdfViewPluginBase::edit_mode;
using PdfViewPluginBase::engine;
using PdfViewPluginBase::full_frame;
using PdfViewPluginBase::HandleMessage;
- using PdfViewPluginBase::InitializeEngine;
- using PdfViewPluginBase::set_document_load_state;
- using PdfViewPluginBase::set_full_frame;
+ using PdfViewPluginBase::LoadUrl;
+ using PdfViewPluginBase::SetZoom;
+ using PdfViewPluginBase::UpdateGeometryOnPluginRectChanged;
+ using PdfViewPluginBase::UpdateScroll;
+
+ MOCK_METHOD(std::string, GetURL, (), (override));
MOCK_METHOD(bool, Confirm, (const std::string&), (override));
@@ -244,6 +183,11 @@ class FakePdfViewPluginBase : public PdfViewPluginBase {
(const base::Location&, ResultCallback, int32_t, base::TimeDelta),
(override));
+ MOCK_METHOD(std::unique_ptr<PDFiumEngine>,
+ CreateEngine,
+ (PDFEngine::Client*, PDFiumFormFiller::ScriptOption),
+ (override));
+
base::WeakPtr<PdfViewPluginBase> GetWeakPtr() override {
return weak_factory_.GetWeakPtr();
}
@@ -253,8 +197,6 @@ class FakePdfViewPluginBase : public PdfViewPluginBase {
(),
(override));
- MOCK_METHOD(void, DidOpen, (std::unique_ptr<UrlLoader>, int32_t), (override));
-
void SendMessage(base::Value message) override {
sent_messages_.push_back(std::move(message));
}
@@ -283,6 +225,13 @@ class FakePdfViewPluginBase : public PdfViewPluginBase {
(const AccessibilityViewportInfo&),
(override));
+ MOCK_METHOD(void, NotifyFindResultsChanged, (int, bool), (override));
+
+ MOCK_METHOD(void,
+ NotifyFindTickmarks,
+ (const std::vector<gfx::Rect>&),
+ (override));
+
MOCK_METHOD(void, SetContentRestrictions, (int), (override));
MOCK_METHOD(void, SetPluginCanSave, (bool), (override));
@@ -302,6 +251,8 @@ class FakePdfViewPluginBase : public PdfViewPluginBase {
MOCK_METHOD(void, UserMetricsRecordAction, (const std::string&), (override));
+ void clear_sent_messages() { sent_messages_.clear(); }
+
const std::vector<base::Value>& sent_messages() const {
return sent_messages_;
}
@@ -312,6 +263,17 @@ class FakePdfViewPluginBase : public PdfViewPluginBase {
base::WeakPtrFactory<FakePdfViewPluginBase> weak_factory_{this};
};
+class MockUrlLoader : public UrlLoader {
+ public:
+ MOCK_METHOD(void, GrantUniversalAccess, (), (override));
+ MOCK_METHOD(void, Open, (const UrlRequest&, ResultCallback), (override));
+ MOCK_METHOD(void,
+ ReadResponseBody,
+ (base::span<char>, ResultCallback),
+ (override));
+ MOCK_METHOD(void, Close, (), (override));
+};
+
base::Value CreateExpectedFormTextFieldFocusChangeResponse() {
base::Value message(base::Value::Type::DICTIONARY);
message.SetStringKey("type", "formFocusChange");
@@ -392,13 +354,6 @@ base::Value CreateExpectedNoMetadataResponse() {
return message;
}
-base::Value CreateExpectedLoadingProgressResponse() {
- base::Value message(base::Value::Type::DICTIONARY);
- message.SetStringKey("type", "loadProgress");
- message.SetDoubleKey("progress", 100);
- return message;
-}
-
base::Value CreateSaveRequestMessage(PdfViewPluginBase::SaveRequestType type,
const std::string& token) {
base::Value message(base::Value::Type::DICTIONARY);
@@ -413,8 +368,8 @@ base::Value CreateExpectedSaveToBufferResponse(const std::string& token) {
expected_response.SetStringKey("type", "saveData");
expected_response.SetStringKey("token", token);
expected_response.SetStringKey("fileName", kDefaultDownloadFileName);
- expected_response.SetKey("dataToSave",
- base::Value(base::make_span(kSaveData)));
+ expected_response.SetKey(
+ "dataToSave", base::Value(base::make_span(TestPDFiumEngine::kSaveData)));
return expected_response;
}
@@ -435,9 +390,26 @@ class PdfViewPluginBaseTest : public testing::Test {
class PdfViewPluginBaseWithEngineTest : public PdfViewPluginBaseTest {
public:
void SetUp() override {
- std::unique_ptr<TestPDFiumEngine> engine =
- std::make_unique<TestPDFiumEngine>(&fake_plugin_);
- fake_plugin_.InitializeEngine(std::move(engine));
+ auto engine =
+ std::make_unique<testing::NiceMock<TestPDFiumEngine>>(&fake_plugin_);
+ fake_plugin_.InitializeEngineForTesting(std::move(engine));
+ }
+
+ protected:
+ void SendDefaultViewportMessage() {
+ fake_plugin_.HandleMessage(base::test::ParseJson(R"({
+ "type": "viewport",
+ "userInitiated": false,
+ "zoom": 1,
+ "layoutOptions": {
+ "direction": 2,
+ "defaultPageOrientation": 0,
+ "twoUpViewEnabled": false,
+ },
+ "xOffset": 0,
+ "yOffset": 0,
+ "pinchPhase": 0,
+ })"));
}
};
@@ -454,7 +426,7 @@ class PdfViewPluginBaseWithDocInfoTest
void SetUp() override {
std::unique_ptr<TestPDFiumEngineWithDocInfo> engine =
std::make_unique<TestPDFiumEngineWithDocInfo>(&fake_plugin_);
- fake_plugin_.InitializeEngine(std::move(engine));
+ fake_plugin_.InitializeEngineForTesting(std::move(engine));
// Initialize some arbitrary document information for the engine.
static_cast<TestPDFiumEngineWithDocInfo*>(fake_plugin_.engine())
@@ -465,8 +437,92 @@ class PdfViewPluginBaseWithDocInfoTest
using PdfViewPluginBaseWithoutDocInfoTest =
PdfViewPluginBaseWithScopedLocaleTest;
+TEST_F(PdfViewPluginBaseTest, LoadUrl) {
+ UrlRequest saved_request;
+ EXPECT_CALL(fake_plugin_, CreateUrlLoaderInternal)
+ .WillOnce([&saved_request]() {
+ auto mock_loader = std::make_unique<testing::NiceMock<MockUrlLoader>>();
+ EXPECT_CALL(*mock_loader, Open)
+ .WillOnce(testing::SaveArg<0>(&saved_request));
+ return mock_loader;
+ });
+
+ // Note that `is_print_preview` only controls the load callback. */
+ fake_plugin_.LoadUrl("fake-url", /*is_print_preview=*/false);
+
+ EXPECT_EQ("fake-url", saved_request.url);
+ EXPECT_EQ("GET", saved_request.method);
+ EXPECT_TRUE(saved_request.ignore_redirects);
+ EXPECT_EQ("", saved_request.custom_referrer_url);
+ EXPECT_EQ("", saved_request.headers);
+ EXPECT_EQ("", saved_request.body);
+ EXPECT_LE(saved_request.buffer_lower_threshold,
+ saved_request.buffer_upper_threshold);
+}
+
+TEST_F(PdfViewPluginBaseTest, DocumentLoadProgress) {
+ fake_plugin_.DocumentLoadProgress(10, 200);
+
+ EXPECT_THAT(fake_plugin_.sent_messages(), ElementsAre(base::test::IsJson(R"({
+ "type": "loadProgress",
+ "progress": 5.0,
+ })")));
+}
+
+TEST_F(PdfViewPluginBaseTest, DocumentLoadProgressIgnoreSmall) {
+ fake_plugin_.DocumentLoadProgress(2, 100);
+ fake_plugin_.clear_sent_messages();
+
+ fake_plugin_.DocumentLoadProgress(3, 100);
+
+ EXPECT_THAT(fake_plugin_.sent_messages(), IsEmpty());
+}
+
+TEST_F(PdfViewPluginBaseTest, DocumentLoadProgressMultipleSmall) {
+ fake_plugin_.DocumentLoadProgress(2, 100);
+ fake_plugin_.clear_sent_messages();
+
+ fake_plugin_.DocumentLoadProgress(3, 100);
+ fake_plugin_.DocumentLoadProgress(4, 100);
+
+ EXPECT_THAT(fake_plugin_.sent_messages(), ElementsAre(base::test::IsJson(R"({
+ "type": "loadProgress",
+ "progress": 4.0,
+ })")));
+}
+
+TEST_F(PdfViewPluginBaseTest, DocumentLoadProgressResetByLoadUrl) {
+ fake_plugin_.DocumentLoadProgress(2, 100);
+ fake_plugin_.clear_sent_messages();
+ EXPECT_CALL(fake_plugin_, CreateUrlLoaderInternal).WillOnce([]() {
+ return std::make_unique<testing::NiceMock<MockUrlLoader>>();
+ });
+
+ fake_plugin_.LoadUrl("fake-url", /*is_print_preview=*/false);
+ fake_plugin_.DocumentLoadProgress(3, 100);
+
+ EXPECT_THAT(fake_plugin_.sent_messages(), ElementsAre(base::test::IsJson(R"({
+ "type": "loadProgress",
+ "progress": 3.0,
+ })")));
+}
+
+TEST_F(PdfViewPluginBaseTest,
+ DocumentLoadProgressNotResetByLoadUrlWithPrintPreview) {
+ fake_plugin_.DocumentLoadProgress(2, 100);
+ fake_plugin_.clear_sent_messages();
+ EXPECT_CALL(fake_plugin_, CreateUrlLoaderInternal).WillOnce([]() {
+ return std::make_unique<testing::NiceMock<MockUrlLoader>>();
+ });
+
+ fake_plugin_.LoadUrl("fake-url", /*is_print_preview=*/true);
+ fake_plugin_.DocumentLoadProgress(3, 100);
+
+ EXPECT_THAT(fake_plugin_.sent_messages(), IsEmpty());
+}
+
TEST_F(PdfViewPluginBaseTest, CreateUrlLoaderInFullFrame) {
- fake_plugin_.set_full_frame(true);
+ fake_plugin_.set_full_frame_for_testing(true);
ASSERT_TRUE(fake_plugin_.full_frame());
EXPECT_FALSE(fake_plugin_.GetDidCallStartLoadingForTesting());
@@ -494,13 +550,13 @@ TEST_F(PdfViewPluginBaseTest, CreateUrlLoaderWithoutFullFrame) {
TEST_F(PdfViewPluginBaseWithDocInfoTest,
DocumentLoadCompleteInFullFramePdfViewerWithAccessibilityEnabled) {
// Notify the render frame about document loading.
- fake_plugin_.set_full_frame(true);
+ fake_plugin_.set_full_frame_for_testing(true);
ASSERT_TRUE(fake_plugin_.full_frame());
fake_plugin_.CreateUrlLoader();
ASSERT_FALSE(fake_plugin_.IsPrintPreview());
ASSERT_EQ(PdfViewPluginBase::DocumentLoadState::kLoading,
- fake_plugin_.document_load_state());
+ fake_plugin_.document_load_state_for_testing());
// Change the accessibility state to pending so that accessibility can be
// loaded later.
@@ -518,12 +574,12 @@ TEST_F(PdfViewPluginBaseWithDocInfoTest,
fake_plugin_.DocumentLoadComplete();
EXPECT_EQ(PdfViewPluginBase::DocumentLoadState::kComplete,
- fake_plugin_.document_load_state());
+ fake_plugin_.document_load_state_for_testing());
EXPECT_EQ(PdfViewPluginBase::AccessibilityState::kLoaded,
fake_plugin_.accessibility_state());
// Check all the sent messages.
- ASSERT_EQ(5u, fake_plugin_.sent_messages().size());
+ ASSERT_EQ(4u, fake_plugin_.sent_messages().size());
EXPECT_EQ(CreateExpectedFormTextFieldFocusChangeResponse(),
fake_plugin_.sent_messages()[0]);
EXPECT_EQ(CreateExpectedAttachmentsResponse(),
@@ -532,20 +588,18 @@ TEST_F(PdfViewPluginBaseWithDocInfoTest,
CreateExpectedBookmarksResponse(fake_plugin_.engine()->GetBookmarks()),
fake_plugin_.sent_messages()[2]);
EXPECT_EQ(CreateExpectedMetadataResponse(), fake_plugin_.sent_messages()[3]);
- EXPECT_EQ(CreateExpectedLoadingProgressResponse(),
- fake_plugin_.sent_messages()[4]);
}
TEST_F(PdfViewPluginBaseWithDocInfoTest,
DocumentLoadCompleteInFullFramePdfViewerWithAccessibilityDisabled) {
// Notify the render frame about document loading.
- fake_plugin_.set_full_frame(true);
+ fake_plugin_.set_full_frame_for_testing(true);
ASSERT_TRUE(fake_plugin_.full_frame());
fake_plugin_.CreateUrlLoader();
ASSERT_FALSE(fake_plugin_.IsPrintPreview());
ASSERT_EQ(PdfViewPluginBase::DocumentLoadState::kLoading,
- fake_plugin_.document_load_state());
+ fake_plugin_.document_load_state_for_testing());
ASSERT_EQ(PdfViewPluginBase::AccessibilityState::kOff,
fake_plugin_.accessibility_state());
@@ -560,12 +614,12 @@ TEST_F(PdfViewPluginBaseWithDocInfoTest,
fake_plugin_.DocumentLoadComplete();
EXPECT_EQ(PdfViewPluginBase::DocumentLoadState::kComplete,
- fake_plugin_.document_load_state());
+ fake_plugin_.document_load_state_for_testing());
EXPECT_EQ(PdfViewPluginBase::AccessibilityState::kOff,
fake_plugin_.accessibility_state());
// Check all the sent messages.
- ASSERT_EQ(5u, fake_plugin_.sent_messages().size());
+ ASSERT_EQ(4u, fake_plugin_.sent_messages().size());
EXPECT_EQ(CreateExpectedFormTextFieldFocusChangeResponse(),
fake_plugin_.sent_messages()[0]);
EXPECT_EQ(CreateExpectedAttachmentsResponse(),
@@ -574,8 +628,6 @@ TEST_F(PdfViewPluginBaseWithDocInfoTest,
CreateExpectedBookmarksResponse(fake_plugin_.engine()->GetBookmarks()),
fake_plugin_.sent_messages()[2]);
EXPECT_EQ(CreateExpectedMetadataResponse(), fake_plugin_.sent_messages()[3]);
- EXPECT_EQ(CreateExpectedLoadingProgressResponse(),
- fake_plugin_.sent_messages()[4]);
}
TEST_F(PdfViewPluginBaseWithDocInfoTest,
@@ -585,7 +637,7 @@ TEST_F(PdfViewPluginBaseWithDocInfoTest,
ASSERT_FALSE(fake_plugin_.IsPrintPreview());
ASSERT_EQ(PdfViewPluginBase::DocumentLoadState::kLoading,
- fake_plugin_.document_load_state());
+ fake_plugin_.document_load_state_for_testing());
EXPECT_CALL(fake_plugin_, UserMetricsRecordAction("PDF.LoadSuccess"));
EXPECT_CALL(fake_plugin_, SetFormFieldInFocus(false));
@@ -596,10 +648,10 @@ TEST_F(PdfViewPluginBaseWithDocInfoTest,
fake_plugin_.DocumentLoadComplete();
EXPECT_EQ(PdfViewPluginBase::DocumentLoadState::kComplete,
- fake_plugin_.document_load_state());
+ fake_plugin_.document_load_state_for_testing());
// Check all the sent messages.
- ASSERT_EQ(5u, fake_plugin_.sent_messages().size());
+ ASSERT_EQ(4u, fake_plugin_.sent_messages().size());
EXPECT_EQ(CreateExpectedFormTextFieldFocusChangeResponse(),
fake_plugin_.sent_messages()[0]);
EXPECT_EQ(CreateExpectedAttachmentsResponse(),
@@ -608,8 +660,6 @@ TEST_F(PdfViewPluginBaseWithDocInfoTest,
CreateExpectedBookmarksResponse(fake_plugin_.engine()->GetBookmarks()),
fake_plugin_.sent_messages()[2]);
EXPECT_EQ(CreateExpectedMetadataResponse(), fake_plugin_.sent_messages()[3]);
- EXPECT_EQ(CreateExpectedLoadingProgressResponse(),
- fake_plugin_.sent_messages()[4]);
}
TEST_F(PdfViewPluginBaseWithoutDocInfoTest, DocumentLoadCompletePostMessages) {
@@ -617,33 +667,31 @@ TEST_F(PdfViewPluginBaseWithoutDocInfoTest, DocumentLoadCompletePostMessages) {
ASSERT_FALSE(fake_plugin_.IsPrintPreview());
ASSERT_EQ(PdfViewPluginBase::DocumentLoadState::kLoading,
- fake_plugin_.document_load_state());
+ fake_plugin_.document_load_state_for_testing());
EXPECT_CALL(fake_plugin_, UserMetricsRecordAction("PDF.LoadSuccess"));
EXPECT_CALL(fake_plugin_, SetFormFieldInFocus(false));
fake_plugin_.DocumentLoadComplete();
EXPECT_EQ(PdfViewPluginBase::DocumentLoadState::kComplete,
- fake_plugin_.document_load_state());
+ fake_plugin_.document_load_state_for_testing());
// Check the sent messages when the document doesn't have any metadata,
// attachments or bookmarks.
- ASSERT_EQ(3u, fake_plugin_.sent_messages().size());
+ ASSERT_EQ(2u, fake_plugin_.sent_messages().size());
EXPECT_EQ(CreateExpectedFormTextFieldFocusChangeResponse(),
fake_plugin_.sent_messages()[0]);
EXPECT_EQ(CreateExpectedNoMetadataResponse(),
fake_plugin_.sent_messages()[1]);
- EXPECT_EQ(CreateExpectedLoadingProgressResponse(),
- fake_plugin_.sent_messages()[2]);
}
TEST_F(PdfViewPluginBaseTest, DocumentLoadFailedWithNotifiedRenderFrame) {
// Notify the render frame about document loading.
- fake_plugin_.set_full_frame(true);
+ fake_plugin_.set_full_frame_for_testing(true);
ASSERT_TRUE(fake_plugin_.full_frame());
fake_plugin_.CreateUrlLoader();
ASSERT_EQ(PdfViewPluginBase::DocumentLoadState::kLoading,
- fake_plugin_.document_load_state());
+ fake_plugin_.document_load_state_for_testing());
EXPECT_TRUE(fake_plugin_.GetDidCallStartLoadingForTesting());
EXPECT_CALL(fake_plugin_, UserMetricsRecordAction("PDF.LoadFailure"));
@@ -651,7 +699,7 @@ TEST_F(PdfViewPluginBaseTest, DocumentLoadFailedWithNotifiedRenderFrame) {
fake_plugin_.DocumentLoadFailed();
EXPECT_EQ(PdfViewPluginBase::DocumentLoadState::kFailed,
- fake_plugin_.document_load_state());
+ fake_plugin_.document_load_state_for_testing());
EXPECT_FALSE(fake_plugin_.GetDidCallStartLoadingForTesting());
}
@@ -661,18 +709,18 @@ TEST_F(PdfViewPluginBaseTest, DocumentLoadFailedWithoutNotifiedRenderFrame) {
EXPECT_FALSE(fake_plugin_.GetDidCallStartLoadingForTesting());
ASSERT_EQ(PdfViewPluginBase::DocumentLoadState::kLoading,
- fake_plugin_.document_load_state());
+ fake_plugin_.document_load_state_for_testing());
EXPECT_CALL(fake_plugin_, UserMetricsRecordAction("PDF.LoadFailure"));
EXPECT_CALL(fake_plugin_, PluginDidStopLoading()).Times(0);
fake_plugin_.DocumentLoadFailed();
EXPECT_EQ(PdfViewPluginBase::DocumentLoadState::kFailed,
- fake_plugin_.document_load_state());
+ fake_plugin_.document_load_state_for_testing());
EXPECT_FALSE(fake_plugin_.GetDidCallStartLoadingForTesting());
}
TEST_F(PdfViewPluginBaseTest, DocumentHasUnsupportedFeatureInFullFrame) {
- fake_plugin_.set_full_frame(true);
+ fake_plugin_.set_full_frame_for_testing(true);
ASSERT_TRUE(fake_plugin_.full_frame());
// Arbitrary feature names and their matching metric names.
@@ -738,7 +786,7 @@ TEST_F(PdfViewPluginBaseTest, EnteredEditMode) {
base::Value expected_response(base::Value::Type::DICTIONARY);
expected_response.SetStringKey("type", "setIsEditing");
- EXPECT_TRUE(fake_plugin_.edit_mode());
+ EXPECT_TRUE(fake_plugin_.edit_mode_for_testing());
ASSERT_EQ(1u, fake_plugin_.sent_messages().size());
EXPECT_EQ(expected_response, fake_plugin_.sent_messages()[0]);
}
@@ -747,7 +795,7 @@ using PdfViewPluginBaseSaveTest = PdfViewPluginBaseWithEngineTest;
#if BUILDFLAG(ENABLE_INK)
TEST_F(PdfViewPluginBaseSaveTest, SaveAnnotationInNonEditMode) {
- ASSERT_FALSE(fake_plugin_.edit_mode());
+ ASSERT_FALSE(fake_plugin_.edit_mode_for_testing());
static constexpr char kSaveAnnotInNonEditModeToken[] =
"save-annot-in-non-edit-mode-token";
@@ -766,7 +814,7 @@ TEST_F(PdfViewPluginBaseSaveTest, SaveAnnotationInNonEditMode) {
TEST_F(PdfViewPluginBaseSaveTest, SaveAnnotationInEditMode) {
fake_plugin_.EnteredEditMode();
- ASSERT_TRUE(fake_plugin_.edit_mode());
+ ASSERT_TRUE(fake_plugin_.edit_mode_for_testing());
static constexpr char kSaveAnnotInEditModeToken[] =
"save-annot-in-edit-mode-token";
@@ -785,7 +833,7 @@ TEST_F(PdfViewPluginBaseSaveTest, SaveAnnotationInEditMode) {
#endif // BUILDFLAG(ENABLE_INK)
TEST_F(PdfViewPluginBaseSaveTest, SaveOriginalInNonEditMode) {
- ASSERT_FALSE(fake_plugin_.edit_mode());
+ ASSERT_FALSE(fake_plugin_.edit_mode_for_testing());
static constexpr char kSaveOriginalInNonEditModeToken[] =
"save-original-in-non-edit-mode-token";
@@ -806,7 +854,7 @@ TEST_F(PdfViewPluginBaseSaveTest, SaveOriginalInNonEditMode) {
TEST_F(PdfViewPluginBaseSaveTest, SaveOriginalInEditMode) {
fake_plugin_.EnteredEditMode();
- ASSERT_TRUE(fake_plugin_.edit_mode());
+ ASSERT_TRUE(fake_plugin_.edit_mode_for_testing());
static constexpr char kSaveOriginalInEditModeToken[] =
"save-original-in-edit-mode-token";
@@ -828,7 +876,7 @@ TEST_F(PdfViewPluginBaseSaveTest, SaveOriginalInEditMode) {
#if BUILDFLAG(ENABLE_INK)
TEST_F(PdfViewPluginBaseSaveTest, SaveEditedInNonEditMode) {
- ASSERT_FALSE(fake_plugin_.edit_mode());
+ ASSERT_FALSE(fake_plugin_.edit_mode_for_testing());
static constexpr char kSaveEditedInNonEditModeToken[] =
"save-edited-in-non-edit-mode";
@@ -847,7 +895,7 @@ TEST_F(PdfViewPluginBaseSaveTest, SaveEditedInNonEditMode) {
TEST_F(PdfViewPluginBaseSaveTest, SaveEditedInEditMode) {
fake_plugin_.EnteredEditMode();
- ASSERT_TRUE(fake_plugin_.edit_mode());
+ ASSERT_TRUE(fake_plugin_.edit_mode_for_testing());
static constexpr char kSaveEditedInEditModeToken[] =
"save-edited-in-edit-mode-token";
@@ -874,6 +922,284 @@ TEST_F(PdfViewPluginBaseTest, HandleSetBackgroundColorMessage) {
EXPECT_EQ(kNewBackgroundColor, fake_plugin_.GetBackgroundColor());
}
+TEST_F(PdfViewPluginBaseWithEngineTest,
+ HandleViewportMessageBeforeDocumentLoadComplete) {
+ auto* engine = static_cast<TestPDFiumEngine*>(fake_plugin_.engine());
+ EXPECT_CALL(*engine, ApplyDocumentLayout(DocumentLayout::Options()));
+
+ fake_plugin_.HandleMessage(base::test::ParseJson(R"({
+ "type": "viewport",
+ "userInitiated": false,
+ "zoom": 1,
+ "layoutOptions": {
+ "direction": 0,
+ "defaultPageOrientation": 0,
+ "twoUpViewEnabled": false,
+ },
+ "xOffset": 0,
+ "yOffset": 0,
+ "pinchPhase": 0,
+ })"));
+
+ EXPECT_THAT(fake_plugin_.sent_messages(), IsEmpty());
+}
+
+TEST_F(PdfViewPluginBaseWithEngineTest,
+ HandleViewportMessageAfterDocumentLoadComplete) {
+ auto* engine = static_cast<TestPDFiumEngine*>(fake_plugin_.engine());
+ EXPECT_CALL(*engine, ApplyDocumentLayout(DocumentLayout::Options()));
+
+ fake_plugin_.DocumentLoadComplete();
+ fake_plugin_.clear_sent_messages();
+
+ fake_plugin_.HandleMessage(base::test::ParseJson(R"({
+ "type": "viewport",
+ "userInitiated": false,
+ "zoom": 1,
+ "layoutOptions": {
+ "direction": 0,
+ "defaultPageOrientation": 0,
+ "twoUpViewEnabled": false,
+ },
+ "xOffset": 0,
+ "yOffset": 0,
+ "pinchPhase": 0,
+ })"));
+
+ EXPECT_THAT(fake_plugin_.sent_messages(), ElementsAre(base::test::IsJson(R"({
+ "type": "loadProgress",
+ "progress": 100.0,
+ })")));
+}
+
+TEST_F(PdfViewPluginBaseWithEngineTest, HandleViewportMessageSubsequently) {
+ auto* engine = static_cast<TestPDFiumEngine*>(fake_plugin_.engine());
+
+ fake_plugin_.HandleMessage(base::test::ParseJson(R"({
+ "type": "viewport",
+ "userInitiated": false,
+ "zoom": 1,
+ "layoutOptions": {
+ "direction": 0,
+ "defaultPageOrientation": 0,
+ "twoUpViewEnabled": false,
+ },
+ "xOffset": 0,
+ "yOffset": 0,
+ "pinchPhase": 0,
+ })"));
+ fake_plugin_.clear_sent_messages();
+
+ DocumentLayout::Options two_up_options;
+ two_up_options.set_page_spread(DocumentLayout::PageSpread::kTwoUpOdd);
+ EXPECT_CALL(*engine, ApplyDocumentLayout(two_up_options));
+
+ fake_plugin_.HandleMessage(base::test::ParseJson(R"({
+ "type": "viewport",
+ "userInitiated": false,
+ "zoom": 1,
+ "layoutOptions": {
+ "direction": 0,
+ "defaultPageOrientation": 0,
+ "twoUpViewEnabled": true,
+ },
+ "xOffset": 0,
+ "yOffset": 0,
+ "pinchPhase": 0,
+ })"));
+
+ EXPECT_THAT(fake_plugin_.sent_messages(), IsEmpty());
+}
+
+TEST_F(PdfViewPluginBaseWithEngineTest, HandleViewportMessageScroll) {
+ auto* engine = static_cast<TestPDFiumEngine*>(fake_plugin_.engine());
+ EXPECT_CALL(*engine, ApplyDocumentLayout)
+ .WillRepeatedly(Return(gfx::Size(16, 9)));
+ EXPECT_CALL(*engine, ScrolledToXPosition(2));
+ EXPECT_CALL(*engine, ScrolledToYPosition(3));
+
+ fake_plugin_.HandleMessage(base::test::ParseJson(R"({
+ "type": "viewport",
+ "userInitiated": false,
+ "zoom": 1,
+ "layoutOptions": {
+ "direction": 2,
+ "defaultPageOrientation": 0,
+ "twoUpViewEnabled": false,
+ },
+ "xOffset": 2,
+ "yOffset": 3,
+ "pinchPhase": 0,
+ })"));
+}
+
+TEST_F(PdfViewPluginBaseWithEngineTest,
+ HandleViewportMessageScrollRightToLeft) {
+ auto* engine = static_cast<TestPDFiumEngine*>(fake_plugin_.engine());
+ EXPECT_CALL(*engine, ApplyDocumentLayout)
+ .WillRepeatedly(Return(gfx::Size(16, 9)));
+ EXPECT_CALL(*engine, ScrolledToXPosition(2));
+ EXPECT_CALL(*engine, ScrolledToYPosition(3));
+
+ fake_plugin_.HandleMessage(base::test::ParseJson(R"({
+ "type": "viewport",
+ "userInitiated": false,
+ "zoom": 1,
+ "layoutOptions": {
+ "direction": 1,
+ "defaultPageOrientation": 0,
+ "twoUpViewEnabled": false,
+ },
+ "xOffset": 2,
+ "yOffset": 3,
+ "pinchPhase": 0,
+ })"));
+}
+
+TEST_F(PdfViewPluginBaseWithEngineTest,
+ HandleViewportMessageScrollRightToLeftInPrintPreview) {
+ auto* engine = static_cast<TestPDFiumEngine*>(fake_plugin_.engine());
+ EXPECT_CALL(*engine, ApplyDocumentLayout)
+ .WillRepeatedly(Return(gfx::Size(16, 9)));
+ EXPECT_CALL(*engine, ScrolledToXPosition(14));
+ EXPECT_CALL(*engine, ScrolledToYPosition(3));
+ EXPECT_CALL(fake_plugin_, IsPrintPreview).WillRepeatedly(Return(true));
+
+ fake_plugin_.HandleMessage(base::test::ParseJson(R"({
+ "type": "viewport",
+ "userInitiated": false,
+ "zoom": 1,
+ "layoutOptions": {
+ "direction": 1,
+ "defaultPageOrientation": 0,
+ "twoUpViewEnabled": false,
+ },
+ "xOffset": -2,
+ "yOffset": 3,
+ "pinchPhase": 0,
+ })"));
+}
+
+TEST_F(PdfViewPluginBaseWithEngineTest, UpdateScroll) {
+ auto* engine = static_cast<TestPDFiumEngine*>(fake_plugin_.engine());
+ EXPECT_CALL(*engine, ScrolledToXPosition(0));
+ EXPECT_CALL(*engine, ScrolledToYPosition(0));
+
+ fake_plugin_.UpdateScroll({0, 0});
+}
+
+TEST_F(PdfViewPluginBaseWithEngineTest, UpdateScrollStopped) {
+ auto* engine = static_cast<TestPDFiumEngine*>(fake_plugin_.engine());
+ EXPECT_CALL(*engine, ScrolledToXPosition).Times(0);
+ EXPECT_CALL(*engine, ScrolledToYPosition).Times(0);
+
+ fake_plugin_.HandleMessage(base::test::ParseJson(R"({
+ "type": "stopScrolling",
+ })"));
+ fake_plugin_.UpdateScroll({0, 0});
+}
+
+TEST_F(PdfViewPluginBaseWithEngineTest, UpdateScrollUnderflow) {
+ auto* engine = static_cast<TestPDFiumEngine*>(fake_plugin_.engine());
+ EXPECT_CALL(*engine, ApplyDocumentLayout)
+ .WillRepeatedly(Return(gfx::Size(16, 9)));
+ SendDefaultViewportMessage();
+ EXPECT_CALL(*engine, ScrolledToXPosition(0));
+ EXPECT_CALL(*engine, ScrolledToYPosition(0));
+
+ fake_plugin_.UpdateScroll({-1, -1});
+}
+
+TEST_F(PdfViewPluginBaseWithEngineTest, UpdateScrollOverflow) {
+ auto* engine = static_cast<TestPDFiumEngine*>(fake_plugin_.engine());
+ fake_plugin_.UpdateGeometryOnPluginRectChanged({3, 2}, 1.0f);
+ EXPECT_CALL(*engine, ApplyDocumentLayout)
+ .WillRepeatedly(Return(gfx::Size(16, 9)));
+ SendDefaultViewportMessage();
+
+ EXPECT_CALL(*engine, ScrolledToXPosition(13));
+ EXPECT_CALL(*engine, ScrolledToYPosition(7));
+
+ fake_plugin_.UpdateScroll({14, 8});
+}
+
+TEST_F(PdfViewPluginBaseWithEngineTest, UpdateScrollOverflowZoomed) {
+ auto* engine = static_cast<TestPDFiumEngine*>(fake_plugin_.engine());
+ fake_plugin_.UpdateGeometryOnPluginRectChanged({3, 2}, 1.0f);
+ EXPECT_CALL(*engine, ApplyDocumentLayout)
+ .WillRepeatedly(Return(gfx::Size(16, 9)));
+ SendDefaultViewportMessage();
+ fake_plugin_.SetZoom(2.0);
+
+ EXPECT_CALL(*engine, ScrolledToXPosition(29));
+ EXPECT_CALL(*engine, ScrolledToYPosition(16));
+
+ fake_plugin_.UpdateScroll({30, 17});
+}
+
+TEST_F(PdfViewPluginBaseWithEngineTest, UpdateScrollScaled) {
+ auto* engine = static_cast<TestPDFiumEngine*>(fake_plugin_.engine());
+ fake_plugin_.UpdateGeometryOnPluginRectChanged({3, 2}, 2.0f);
+ EXPECT_CALL(*engine, ApplyDocumentLayout)
+ .WillRepeatedly(Return(gfx::Size(16, 9)));
+ SendDefaultViewportMessage();
+
+ EXPECT_CALL(*engine, ScrolledToXPosition(4));
+ EXPECT_CALL(*engine, ScrolledToYPosition(2));
+
+ fake_plugin_.UpdateScroll({2, 1});
+}
+
+TEST_F(PdfViewPluginBaseTest, HandleResetPrintPreviewModeMessage) {
+ EXPECT_CALL(fake_plugin_, IsPrintPreview).WillRepeatedly(Return(true));
+ EXPECT_CALL(fake_plugin_, CreateUrlLoaderInternal).WillRepeatedly([]() {
+ return std::make_unique<testing::NiceMock<MockUrlLoader>>();
+ });
+
+ auto engine =
+ std::make_unique<testing::NiceMock<TestPDFiumEngine>>(&fake_plugin_);
+ EXPECT_CALL(*engine, ZoomUpdated);
+ EXPECT_CALL(*engine, PageOffsetUpdated);
+ EXPECT_CALL(*engine, PluginSizeUpdated);
+ EXPECT_CALL(*engine, SetGrayscale(false));
+ EXPECT_CALL(fake_plugin_,
+ CreateEngine(&fake_plugin_,
+ PDFiumFormFiller::ScriptOption::kNoJavaScript))
+ .WillOnce(Return(ByMove(std::move(engine))));
+
+ fake_plugin_.HandleMessage(base::test::ParseJson(R"({
+ "type": "resetPrintPreviewMode",
+ "url": "chrome-untrusted://print/0/0/print.pdf",
+ "grayscale": false,
+ "pageCount": 1,
+ })"));
+}
+
+TEST_F(PdfViewPluginBaseTest, HandleResetPrintPreviewModeMessageSetGrayscale) {
+ EXPECT_CALL(fake_plugin_, IsPrintPreview).WillRepeatedly(Return(true));
+ EXPECT_CALL(fake_plugin_, CreateUrlLoaderInternal).WillRepeatedly([]() {
+ return std::make_unique<testing::NiceMock<MockUrlLoader>>();
+ });
+
+ auto engine =
+ std::make_unique<testing::NiceMock<TestPDFiumEngine>>(&fake_plugin_);
+ EXPECT_CALL(*engine, ZoomUpdated);
+ EXPECT_CALL(*engine, PageOffsetUpdated);
+ EXPECT_CALL(*engine, PluginSizeUpdated);
+ EXPECT_CALL(*engine, SetGrayscale(true));
+ EXPECT_CALL(fake_plugin_,
+ CreateEngine(&fake_plugin_,
+ PDFiumFormFiller::ScriptOption::kNoJavaScript))
+ .WillOnce(Return(ByMove(std::move(engine))));
+
+ fake_plugin_.HandleMessage(base::test::ParseJson(R"({
+ "type": "resetPrintPreviewMode",
+ "url": "chrome-untrusted://print/0/0/print.pdf",
+ "grayscale": true,
+ "pageCount": 1,
+ })"));
+}
+
TEST_F(PdfViewPluginBaseWithEngineTest, GetContentRestrictions) {
auto* engine = static_cast<TestPDFiumEngine*>(fake_plugin_.engine());
static constexpr int kContentRestrictionCutPaste =
@@ -932,7 +1258,7 @@ TEST_F(PdfViewPluginBaseWithEngineTest, GetAccessibilityDocInfo) {
engine->SetPermissions({});
AccessibilityDocInfo doc_info = fake_plugin_.GetAccessibilityDocInfo();
- EXPECT_EQ(kPageNumber, doc_info.page_count);
+ EXPECT_EQ(TestPDFiumEngine::kPageNumber, doc_info.page_count);
EXPECT_FALSE(doc_info.text_accessible);
EXPECT_FALSE(doc_info.text_copyable);
@@ -940,7 +1266,7 @@ TEST_F(PdfViewPluginBaseWithEngineTest, GetAccessibilityDocInfo) {
engine->SetPermissions({DocumentPermission::kCopy});
doc_info = fake_plugin_.GetAccessibilityDocInfo();
- EXPECT_EQ(kPageNumber, doc_info.page_count);
+ EXPECT_EQ(TestPDFiumEngine::kPageNumber, doc_info.page_count);
EXPECT_FALSE(doc_info.text_accessible);
EXPECT_TRUE(doc_info.text_copyable);
@@ -948,7 +1274,7 @@ TEST_F(PdfViewPluginBaseWithEngineTest, GetAccessibilityDocInfo) {
engine->SetPermissions({DocumentPermission::kCopyAccessible});
doc_info = fake_plugin_.GetAccessibilityDocInfo();
- EXPECT_EQ(kPageNumber, doc_info.page_count);
+ EXPECT_EQ(TestPDFiumEngine::kPageNumber, doc_info.page_count);
EXPECT_TRUE(doc_info.text_accessible);
EXPECT_FALSE(doc_info.text_copyable);
@@ -957,9 +1283,79 @@ TEST_F(PdfViewPluginBaseWithEngineTest, GetAccessibilityDocInfo) {
{DocumentPermission::kCopy, DocumentPermission::kCopyAccessible});
doc_info = fake_plugin_.GetAccessibilityDocInfo();
- EXPECT_EQ(kPageNumber, doc_info.page_count);
+ EXPECT_EQ(TestPDFiumEngine::kPageNumber, doc_info.page_count);
EXPECT_TRUE(doc_info.text_accessible);
EXPECT_TRUE(doc_info.text_copyable);
}
+class PdfViewPluginBaseSubmitFormTest : public PdfViewPluginBaseTest {
+ public:
+ void SubmitForm(const std::string& url,
+ base::StringPiece form_data = "data") {
+ EXPECT_CALL(fake_plugin_, CreateUrlLoaderInternal).WillOnce([this]() {
+ auto mock_loader = std::make_unique<testing::NiceMock<MockUrlLoader>>();
+ EXPECT_CALL(*mock_loader, Open).WillOnce(testing::SaveArg<0>(&request_));
+ return mock_loader;
+ });
+
+ fake_plugin_.SubmitForm(url, form_data.data(), form_data.size());
+ }
+
+ void SubmitFailingForm(const std::string& url) {
+ EXPECT_CALL(fake_plugin_, CreateUrlLoaderInternal).Times(0);
+ constexpr char kFormData[] = "form data";
+ fake_plugin_.SubmitForm(url, kFormData, base::size(kFormData));
+ }
+
+ protected:
+ UrlRequest request_;
+};
+
+TEST_F(PdfViewPluginBaseSubmitFormTest, RequestMethodAndBody) {
+ EXPECT_CALL(fake_plugin_, GetURL)
+ .WillOnce(Return("https://www.example.com/path/to/the.pdf"));
+ constexpr char kFormData[] = "form data";
+ SubmitForm(/*url=*/"", kFormData);
+ EXPECT_EQ(request_.method, "POST");
+ EXPECT_THAT(request_.body, StrEq(kFormData));
+}
+
+TEST_F(PdfViewPluginBaseSubmitFormTest, RelativeUrl) {
+ EXPECT_CALL(fake_plugin_, GetURL)
+ .WillOnce(Return("https://www.example.com/path/to/the.pdf"));
+ SubmitForm("relative_endpoint");
+ EXPECT_EQ(request_.url, "https://www.example.com/path/to/relative_endpoint");
+}
+
+TEST_F(PdfViewPluginBaseSubmitFormTest, NoRelativeUrl) {
+ EXPECT_CALL(fake_plugin_, GetURL)
+ .WillOnce(Return("https://www.example.com/path/to/the.pdf"));
+ SubmitForm("");
+ EXPECT_EQ(request_.url, "https://www.example.com/path/to/the.pdf");
+}
+
+TEST_F(PdfViewPluginBaseSubmitFormTest, AbsoluteUrl) {
+ EXPECT_CALL(fake_plugin_, GetURL)
+ .WillOnce(Return("https://a.example.com/path/to/the.pdf"));
+ SubmitForm("https://b.example.com/relative_endpoint");
+ EXPECT_EQ(request_.url, "https://b.example.com/relative_endpoint");
+}
+
+TEST_F(PdfViewPluginBaseSubmitFormTest, EmptyDocumentUrl) {
+ EXPECT_CALL(fake_plugin_, GetURL).WillOnce(Return(std::string()));
+ SubmitFailingForm("relative_endpoint");
+}
+
+TEST_F(PdfViewPluginBaseSubmitFormTest, RelativeUrlInvalidDocumentUrl) {
+ EXPECT_CALL(fake_plugin_, GetURL)
+ .WillOnce(Return(R"(https://www.%B%Ad.com/path/to/the.pdf)"));
+ SubmitFailingForm("relative_endpoint");
+}
+
+TEST_F(PdfViewPluginBaseSubmitFormTest, AbsoluteUrlInvalidDocumentUrl) {
+ EXPECT_CALL(fake_plugin_, GetURL)
+ .WillOnce(Return(R"(https://www.%B%Ad.com/path/to/the.pdf)"));
+ SubmitFailingForm("https://wwww.example.com");
+}
+
} // namespace chrome_pdf
diff --git a/chromium/pdf/pdf_view_web_plugin.cc b/chromium/pdf/pdf_view_web_plugin.cc
index 470e5ddfa7d..29f922ed743 100644
--- a/chromium/pdf/pdf_view_web_plugin.cc
+++ b/chromium/pdf/pdf_view_web_plugin.cc
@@ -13,6 +13,7 @@
#include <vector>
#include "base/check_op.h"
+#include "base/i18n/char_iterator.h"
#include "base/i18n/string_search.h"
#include "base/no_destructor.h"
#include "base/notreached.h"
@@ -47,6 +48,7 @@
#include "third_party/blink/public/common/metrics/document_update_reason.h"
#include "third_party/blink/public/mojom/input/focus_type.mojom-shared.h"
#include "third_party/blink/public/platform/web_input_event_result.h"
+#include "third_party/blink/public/platform/web_security_origin.h"
#include "third_party/blink/public/platform/web_string.h"
#include "third_party/blink/public/platform/web_text_input_type.h"
#include "third_party/blink/public/platform/web_url.h"
@@ -56,6 +58,7 @@
#include "third_party/blink/public/web/web_associated_url_loader.h"
#include "third_party/blink/public/web/web_associated_url_loader_options.h"
#include "third_party/blink/public/web/web_document.h"
+#include "third_party/blink/public/web/web_frame.h"
#include "third_party/blink/public/web/web_frame_widget.h"
#include "third_party/blink/public/web/web_local_frame.h"
#include "third_party/blink/public/web/web_local_frame_client.h"
@@ -64,18 +67,19 @@
#include "third_party/blink/public/web/web_print_preset_options.h"
#include "third_party/blink/public/web/web_view.h"
#include "third_party/blink/public/web/web_widget.h"
+#include "third_party/skia/include/core/SkColor.h"
#include "third_party/skia/include/core/SkRect.h"
#include "third_party/skia/include/core/SkRefCnt.h"
#include "ui/base/cursor/cursor.h"
#include "ui/base/cursor/mojom/cursor_type.mojom-shared.h"
#include "ui/display/screen_info.h"
+#include "ui/events/base_event_utils.h"
#include "ui/events/blink/blink_event_util.h"
#include "ui/events/keycodes/keyboard_codes.h"
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/geometry/rect.h"
-#include "ui/gfx/geometry/scroll_offset.h"
+#include "ui/gfx/geometry/skia_conversions.h"
#include "ui/gfx/range/range.h"
-#include "ui/gfx/skia_util.h"
#include "url/gurl.h"
#include "v8/include/v8.h"
@@ -141,6 +145,11 @@ class BlinkContainerWrapper final : public PdfViewWebPlugin::ContainerWrapper {
void Invalidate() override { container_->Invalidate(); }
+ void RequestTouchEventType(
+ blink::WebPluginContainer::TouchEventRequestType request_type) override {
+ container_->RequestTouchEventType(request_type);
+ }
+
void ReportFindInPageMatchCount(int identifier,
int total,
bool final_update) override {
@@ -166,16 +175,20 @@ class BlinkContainerWrapper final : public PdfViewWebPlugin::ContainerWrapper {
}
void Alert(const blink::WebString& message) override {
- GetFrame()->Alert(message);
+ blink::WebLocalFrame* frame = GetFrame();
+ if (frame)
+ frame->Alert(message);
}
bool Confirm(const blink::WebString& message) override {
- return GetFrame()->Confirm(message);
+ blink::WebLocalFrame* frame = GetFrame();
+ return frame && frame->Confirm(message);
}
blink::WebString Prompt(const blink::WebString& message,
const blink::WebString& default_value) override {
- return GetFrame()->Prompt(message, default_value);
+ blink::WebLocalFrame* frame = GetFrame();
+ return frame ? frame->Prompt(message, default_value) : blink::WebString();
}
void TextSelectionChanged(const blink::WebString& selection_text,
@@ -210,6 +223,18 @@ class BlinkContainerWrapper final : public PdfViewWebPlugin::ContainerWrapper {
widget->UpdateSelectionBounds();
}
+ std::string GetEmbedderOriginString() override {
+ auto* frame = GetFrame();
+ if (!frame)
+ return {};
+
+ auto* parent_frame = frame->Parent();
+ if (!parent_frame)
+ return {};
+
+ return GURL(parent_frame->GetSecurityOrigin().ToString().Utf8()).spec();
+ }
+
blink::WebLocalFrame* GetFrame() override {
return container_->GetDocument().GetFrame();
}
@@ -250,38 +275,30 @@ PdfViewWebPlugin::~PdfViewWebPlugin() = default;
bool PdfViewWebPlugin::Initialize(blink::WebPluginContainer* container) {
DCHECK_EQ(container->Plugin(), this);
- return InitializeCommon(std::make_unique<BlinkContainerWrapper>(container));
+ return InitializeCommon(std::make_unique<BlinkContainerWrapper>(container),
+ nullptr);
}
bool PdfViewWebPlugin::InitializeForTesting(
- std::unique_ptr<ContainerWrapper> container_wrapper) {
- return InitializeCommon(std::move(container_wrapper));
+ std::unique_ptr<ContainerWrapper> container_wrapper,
+ std::unique_ptr<PDFiumEngine> engine) {
+ return InitializeCommon(std::move(container_wrapper), std::move(engine));
}
// Modeled on `OutOfProcessInstance::Init()`.
bool PdfViewWebPlugin::InitializeCommon(
- std::unique_ptr<ContainerWrapper> container_wrapper) {
+ std::unique_ptr<ContainerWrapper> container_wrapper,
+ std::unique_ptr<PDFiumEngine> engine) {
container_wrapper_ = std::move(container_wrapper);
+ post_message_sender_.set_container(Container());
- // Check if the PDF is being loaded in the PDF chrome extension. We only allow
- // the plugin to be loaded in the extension and print preview to avoid
- // exposing sensitive APIs directly to external websites.
- std::string document_url;
- auto* container = Container();
- if (container) {
- GURL maybe_url(container->GetDocument().Url());
- if (maybe_url.is_valid())
- document_url = maybe_url.possibly_invalid_spec();
- }
-
- base::StringPiece document_url_piece(document_url);
- set_is_print_preview(IsPrintPreviewUrl(document_url_piece));
- // TODO(crbug.com/1123621): Consider calling ValidateDocumentUrl() or
- // something like it once the process model has been finalized.
+ // Allow the plugin to handle touch events.
+ container_wrapper_->RequestTouchEventType(
+ blink::WebPluginContainer::kTouchEventRequestTypeRaw);
// Allow the plugin to handle find requests.
- if (container)
- container->UsePluginAsFindHandler();
+ if (Container())
+ Container()->UsePluginAsFindHandler();
absl::optional<ParsedParams> params = ParseWebPluginParams(initial_params_);
@@ -291,16 +308,19 @@ bool PdfViewWebPlugin::InitializeCommon(
if (!params.has_value())
return false;
- set_full_frame(params->full_frame);
- if (params->background_color.has_value())
- SetBackgroundColor(params->background_color.value());
-
PerProcessInitializer::GetInstance().Acquire();
- InitializeEngine(std::make_unique<PDFiumEngine>(this, params->script_option));
- LoadUrl(params->src_url, /*is_print_preview=*/false);
- set_url(params->original_url);
- post_message_sender_.set_container(Container());
+ // TODO(crbug.com/1257666): Implement "has-edits" support.
+ InitializeBase(
+ engine ? std::move(engine)
+ : std::make_unique<PDFiumEngine>(this, params->script_option),
+ /*embedder_origin=*/container_wrapper_->GetEmbedderOriginString(),
+ /*src_url=*/params->src_url,
+ /*original_url=*/params->original_url,
+ /*full_frame=*/params->full_frame,
+ /*background_color=*/
+ params->background_color.value_or(SK_ColorTRANSPARENT),
+ /*has_edits=*/false);
return true;
}
@@ -311,8 +331,8 @@ void PdfViewWebPlugin::Destroy() {
DestroyPreviewEngine();
DestroyEngine();
PerProcessInitializer::GetInstance().Release();
- container_wrapper_.reset();
post_message_sender_.set_container(nullptr);
+ container_wrapper_.reset();
}
delete this;
@@ -344,19 +364,12 @@ void PdfViewWebPlugin::UpdateAllLifecyclePhases(
blink::DocumentUpdateReason reason) {}
void PdfViewWebPlugin::Paint(cc::PaintCanvas* canvas, const gfx::Rect& rect) {
- // The scale level used to convert DIPs to CSS pixels.
- float inverse_scale = 1.0f / (device_scale() * viewport_to_dip_scale_);
-
- // `rect` is in CSS pixels, and the plugin rect is in DIPs. The plugin rect
- // needs to be converted into CSS pixels before calculating the rect area to
- // be invalidated.
- gfx::Rect plugin_rect_in_css_pixels =
- gfx::ScaleToEnclosingRectSafe(plugin_rect(), inverse_scale);
-
// Clip the intersection of the paint rect and the plugin rect, so that
// painting outside the plugin or the paint rect area can be avoided.
+ // Note: `rect` is in CSS pixels. We need to use `css_plugin_rect_`
+ // to calculate the intersection.
SkRect invalidate_rect =
- gfx::RectToSkRect(gfx::IntersectRects(plugin_rect_in_css_pixels, rect));
+ gfx::RectToSkRect(gfx::IntersectRects(css_plugin_rect_, rect));
cc::PaintCanvasAutoRestore auto_restore(canvas, /*save=*/true);
canvas->clipRect(invalidate_rect);
@@ -369,8 +382,8 @@ void PdfViewWebPlugin::Paint(cc::PaintCanvas* canvas, const gfx::Rect& rect) {
return;
}
- if (inverse_scale != 1.0f)
- canvas->scale(inverse_scale, inverse_scale);
+ if (device_to_css_scale_ != 1.0f)
+ canvas->scale(device_to_css_scale_, device_to_css_scale_);
canvas->drawImage(snapshot_, plugin_rect().x(), plugin_rect().y());
}
@@ -379,16 +392,19 @@ void PdfViewWebPlugin::UpdateGeometry(const gfx::Rect& window_rect,
const gfx::Rect& clip_rect,
const gfx::Rect& unobscured_rect,
bool is_visible) {
- float device_scale = container_wrapper_->DeviceScaleFactor();
- viewport_to_dip_scale_ =
- client_->IsUseZoomForDSFEnabled() ? 1.0f / device_scale : 1.0f;
+ // An empty `window_rect` can be received here in the following cases:
+ // - If the embedded plugin size is 0.
+ // - If the embedded plugin size is not 0, it can come from re-layouts during
+ // the plugin initialization.
+ // For either case, there is no need to create a graphic device to display
+ // a PDF in an empty window. Since an empty `window_rect` can cause failure
+ // to create the graphic device, avoid all updates on the geometries and the
+ // device scales used by the plugin, the PaintManager and the PDFiumEngine
+ // unless a non-empty `window_rect` is received.
+ if (window_rect.IsEmpty())
+ return;
- // Note that `window_rect` is in viewport coordinates. It needs to be
- // converted to DIPs before getting passed into
- // PdfViewPluginBase::UpdateGeometryOnViewChanged().
- OnViewportChanged(
- gfx::ScaleToEnclosingRectSafe(window_rect, viewport_to_dip_scale_),
- device_scale);
+ OnViewportChanged(window_rect, container_wrapper_->DeviceScaleFactor());
}
void PdfViewWebPlugin::UpdateFocus(bool focused,
@@ -424,11 +440,11 @@ blink::WebInputEventResult PdfViewWebPlugin::HandleInputEvent(
const blink::WebCoalescedInputEvent& event,
ui::Cursor* cursor) {
// TODO(crbug.com/702993): The input events received by the Pepper plugin
- // already have the device scale applied. The scaling done here should be
- // moved into `PdfViewPluginBase::HandleInputEvent()` once the Pepper plugin
- // is removed.
+ // already have the viewport-to-DIP scale applied. The scaling done here
+ // should be moved into `PdfViewPluginBase::HandleInputEvent()` once the
+ // Pepper plugin is removed.
std::unique_ptr<blink::WebInputEvent> scaled_event =
- ui::ScaleWebInputEvent(event.Event(), device_scale());
+ ui::ScaleWebInputEvent(event.Event(), viewport_to_dip_scale_);
const blink::WebInputEvent& event_to_handle =
scaled_event ? *scaled_event : event.Event();
@@ -556,20 +572,17 @@ bool PdfViewWebPlugin::StartFind(const blink::WebString& search_text,
bool case_sensitive,
int identifier) {
find_identifier_ = identifier;
- engine()->StartFind(search_text.Utf8(), case_sensitive);
- return true;
+ return PdfViewPluginBase::StartFind(search_text.Utf8(), case_sensitive);
}
void PdfViewWebPlugin::SelectFindResult(bool forward, int identifier) {
find_identifier_ = identifier;
- engine()->SelectFindResult(forward);
+ PdfViewPluginBase::SelectFindResult(forward);
}
void PdfViewWebPlugin::StopFind() {
find_identifier_ = -1;
- engine()->StopFind();
- // TODO(crbug.com/1199999): Clear tickmarks on scroller when find is
- // dismissed.
+ PdfViewPluginBase::StopFind();
}
bool PdfViewWebPlugin::CanRotateView() {
@@ -589,28 +602,42 @@ void PdfViewWebPlugin::RotateView(blink::WebPlugin::RotationType type) {
}
}
+bool PdfViewWebPlugin::ShouldDispatchImeEventsToPlugin() {
+ return true;
+}
+
blink::WebTextInputType PdfViewWebPlugin::GetPluginTextInputType() {
return text_input_type_;
}
-void PdfViewWebPlugin::UpdateCursor(ui::mojom::CursorType new_cursor_type) {
- set_cursor_type(new_cursor_type);
+gfx::Rect PdfViewWebPlugin::GetPluginCaretBounds() {
+ return caret_rect_;
}
-void PdfViewWebPlugin::UpdateTickMarks(
- const std::vector<gfx::Rect>& tickmarks) {}
+void PdfViewWebPlugin::ImeSetCompositionForPlugin(
+ const blink::WebString& text,
+ const std::vector<ui::ImeTextSpan>& /*ime_text_spans*/,
+ const gfx::Range& /*replacement_range*/,
+ int /*selection_start*/,
+ int /*selection_end*/) {
+ composition_text_ = text;
+}
-void PdfViewWebPlugin::NotifyNumberOfFindResultsChanged(int total,
- bool final_result) {
- // After stopping search and setting `find_identifier_` to -1 there still may
- // be a NotifyNumberOfFindResultsChanged notification pending from engine.
- // Just ignore them.
- if (find_identifier_ == -1 || !container_wrapper_)
- return;
+void PdfViewWebPlugin::ImeCommitTextForPlugin(
+ const blink::WebString& text,
+ const std::vector<ui::ImeTextSpan>& /*ime_text_spans*/,
+ const gfx::Range& /*replacement_range*/,
+ int /*relative_cursor_pos*/) {
+ HandleImeCommit(text);
+}
- container_wrapper_->ReportFindInPageMatchCount(find_identifier_, total,
- final_result);
- // TODO(crbug.com/1199999): Set tickmarks on scroller.
+void PdfViewWebPlugin::ImeFinishComposingTextForPlugin(
+ bool /*keep_selection*/) {
+ HandleImeCommit(composition_text_);
+}
+
+void PdfViewWebPlugin::UpdateCursor(ui::mojom::CursorType new_cursor_type) {
+ set_cursor_type(new_cursor_type);
}
void PdfViewWebPlugin::NotifySelectedFindResultChanged(int current_find_index) {
@@ -622,6 +649,11 @@ void PdfViewWebPlugin::NotifySelectedFindResultChanged(int current_find_index) {
current_find_index + 1);
}
+void PdfViewWebPlugin::CaretChanged(const gfx::Rect& caret_rect) {
+ caret_rect_ = gfx::ScaleToEnclosingRectSafe(
+ caret_rect + available_area().OffsetFromOrigin(), device_to_css_scale_);
+}
+
void PdfViewWebPlugin::Alert(const std::string& message) {
container_wrapper_->Alert(blink::WebString::FromUTF8(message));
}
@@ -638,10 +670,6 @@ std::string PdfViewWebPlugin::Prompt(const std::string& question,
.Utf8();
}
-void PdfViewWebPlugin::SubmitForm(const std::string& url,
- const void* data,
- int length) {}
-
std::vector<PDFEngine::Client::SearchStringResult>
PdfViewWebPlugin::SearchString(const char16_t* string,
const char16_t* term,
@@ -730,6 +758,10 @@ void PdfViewWebPlugin::UpdateSnapshot(sk_sp<SkImage> snapshot) {
InvalidatePluginContainer();
}
+void PdfViewWebPlugin::EnableAccessibility() {
+ PdfViewPluginBase::EnableAccessibility();
+}
+
void PdfViewWebPlugin::HandleAccessibilityAction(
const AccessibilityActionData& action_data) {
PdfViewPluginBase::HandleAccessibilityAction(action_data);
@@ -745,17 +777,6 @@ std::unique_ptr<UrlLoader> PdfViewWebPlugin::CreateUrlLoaderInternal() {
return loader;
}
-// Modeled on `OutOfProcessInstance::DidOpen()`.
-void PdfViewWebPlugin::DidOpen(std::unique_ptr<UrlLoader> loader,
- int32_t result) {
- if (result == Result::kSuccess) {
- if (!engine()->HandleDocumentLoad(std::move(loader), GetURL()))
- DocumentLoadFailed();
- } else {
- NOTIMPLEMENTED();
- }
-}
-
void PdfViewWebPlugin::SendMessage(base::Value message) {
post_message_sender_.Post(std::move(message));
}
@@ -799,9 +820,36 @@ void PdfViewWebPlugin::SetAccessibilityPageInfo(
void PdfViewWebPlugin::SetAccessibilityViewportInfo(
const AccessibilityViewportInfo& viewport_info) {
- if (!pdf_accessibility_data_handler_)
+ // The accessibility tree cannot be updated within the scope of
+ // `UpdateGeometry`.
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE,
+ base::BindOnce(&PdfViewWebPlugin::OnSetAccessibilityViewportInfo,
+ weak_factory_.GetWeakPtr(), viewport_info));
+}
+
+void PdfViewWebPlugin::NotifyFindResultsChanged(int total, bool final_result) {
+ // After stopping search and setting `find_identifier_` to -1 there still may
+ // be a NotifyNumberOfFindResultsChanged notification pending from engine.
+ // Just ignore them.
+ if (find_identifier_ == -1 || !container_wrapper_)
return;
- pdf_accessibility_data_handler_->SetAccessibilityViewportInfo(viewport_info);
+
+ container_wrapper_->ReportFindInPageMatchCount(find_identifier_, total,
+ final_result);
+}
+void PdfViewWebPlugin::NotifyFindTickmarks(
+ const std::vector<gfx::Rect>& tickmarks) {
+ auto* service = GetPdfService();
+ if (!service)
+ return;
+
+ if (!find_remote_) {
+ mojo::PendingRemote<pdf::mojom::PdfFindInPage> pending_find_remote;
+ service->GetPdfFindInPage(&pending_find_remote);
+ find_remote_.Bind(std::move(pending_find_remote));
+ }
+ find_remote_->SetTickmarks(tickmarks);
}
void PdfViewWebPlugin::SetContentRestrictions(int content_restrictions) {
@@ -864,21 +912,27 @@ void PdfViewWebPlugin::UserMetricsRecordAction(const std::string& action) {
client_->RecordComputedAction(action);
}
-void PdfViewWebPlugin::OnViewportChanged(const gfx::Rect& view_rect,
- float new_device_scale) {
- UpdateGeometryOnViewChanged(view_rect, new_device_scale);
-
- if (IsPrintPreview() && !stop_scrolling()) {
- DCHECK_EQ(new_device_scale, device_scale());
- gfx::ScrollOffset scroll_offset =
- container_wrapper_->GetFrame()->GetScrollOffset();
- scroll_offset.Scale(device_scale());
- set_scroll_position(gfx::Point(scroll_offset.x(), scroll_offset.y()));
- UpdateScroll();
+void PdfViewWebPlugin::OnViewportChanged(
+ const gfx::Rect& plugin_rect_in_css_pixel,
+ float new_device_scale) {
+ css_plugin_rect_ = plugin_rect_in_css_pixel;
+ float css_to_device_pixel_scale;
+ if (client_->IsUseZoomForDSFEnabled()) {
+ viewport_to_dip_scale_ = 1.0f / new_device_scale;
+ device_to_css_scale_ = 1.0f;
+ css_to_device_pixel_scale = 1.0f;
+ } else {
+ viewport_to_dip_scale_ = 1.0f;
+ device_to_css_scale_ = 1.0f / new_device_scale;
+ css_to_device_pixel_scale = new_device_scale;
}
- // Scrolling in the main PDF Viewer UI is already handled by
- // `HandleUpdateScrollMessage()`.
+ // `plugin_rect_in_css_pixel` needs to be converted to device pixels before
+ // getting passed into PdfViewPluginBase::UpdateGeometryOnPluginRectChanged().
+ UpdateGeometryOnPluginRectChanged(
+ gfx::ScaleToEnclosingRectSafe(plugin_rect_in_css_pixel,
+ css_to_device_pixel_scale),
+ new_device_scale);
}
void PdfViewWebPlugin::InvalidatePluginContainer() {
@@ -925,10 +979,43 @@ bool PdfViewWebPlugin::Redo() {
return true;
}
+void PdfViewWebPlugin::HandleImeCommit(const blink::WebString& text) {
+ if (text.IsEmpty())
+ return;
+
+ std::u16string text16 = text.Utf16();
+ composition_text_.Reset();
+
+ size_t i = 0;
+ for (base::i18n::UTF16CharIterator iterator(text16); iterator.Advance();) {
+ blink::WebKeyboardEvent char_event(blink::WebInputEvent::Type::kChar,
+ blink::WebInputEvent::kNoModifiers,
+ ui::EventTimeForNow());
+ char_event.windows_key_code = text16[i];
+ char_event.native_key_code = text16[i];
+
+ for (const size_t char_start = i; i < iterator.array_pos(); ++i) {
+ char_event.text[i - char_start] = text16[i];
+ char_event.unmodified_text[i - char_start] = text16[i];
+ }
+
+ blink::WebCoalescedInputEvent input_event(char_event, ui::LatencyInfo());
+ ui::Cursor dummy_cursor_info;
+ HandleInputEvent(input_event, &dummy_cursor_info);
+ }
+}
+
void PdfViewWebPlugin::OnInvokePrintDialog(int32_t /*result*/) {
client_->Print(Container()->GetElement());
}
+void PdfViewWebPlugin::OnSetAccessibilityViewportInfo(
+ const AccessibilityViewportInfo& viewport_info) {
+ if (!pdf_accessibility_data_handler_)
+ return;
+ pdf_accessibility_data_handler_->SetAccessibilityViewportInfo(viewport_info);
+}
+
pdf::mojom::PdfService* PdfViewWebPlugin::GetPdfService() {
return pdf_service_remote_.is_bound() ? pdf_service_remote_.get() : nullptr;
}
diff --git a/chromium/pdf/pdf_view_web_plugin.h b/chromium/pdf/pdf_view_web_plugin.h
index 2ad39f80101..f0c182f948d 100644
--- a/chromium/pdf/pdf_view_web_plugin.h
+++ b/chromium/pdf/pdf_view_web_plugin.h
@@ -8,11 +8,13 @@
#include <stdint.h>
#include <memory>
+#include <string>
#include <vector>
#include "base/memory/weak_ptr.h"
#include "cc/paint/paint_image.h"
#include "mojo/public/cpp/bindings/associated_remote.h"
+#include "mojo/public/cpp/bindings/remote.h"
#include "pdf/mojom/pdf.mojom.h"
#include "pdf/pdf_accessibility_action_handler.h"
#include "pdf/pdf_view_plugin_base.h"
@@ -23,6 +25,7 @@
#include "third_party/blink/public/platform/web_string.h"
#include "third_party/blink/public/platform/web_text_input_type.h"
#include "third_party/blink/public/web/web_plugin.h"
+#include "third_party/blink/public/web/web_plugin_container.h"
#include "third_party/blink/public/web/web_plugin_params.h"
#include "v8/include/v8.h"
@@ -31,7 +34,6 @@ class WebAssociatedURLLoader;
class WebElement;
class WebLocalFrame;
class WebLocalFrameClient;
-class WebPluginContainer;
class WebURL;
class WebURLRequest;
struct WebAssociatedURLLoaderOptions;
@@ -47,6 +49,7 @@ class MetafileSkia;
namespace chrome_pdf {
+class PDFiumEngine;
class PdfAccessibilityDataHandler;
// Skeleton for a `blink::WebPlugin` to replace `OutOfProcessInstance`.
@@ -65,6 +68,10 @@ class PdfViewWebPlugin final : public PdfViewPluginBase,
// page in it.
virtual void Invalidate() = 0;
+ // Notifies the container about which touch events the plugin accepts.
+ virtual void RequestTouchEventType(
+ blink::WebPluginContainer::TouchEventRequestType request_type) = 0;
+
// Notify the web plugin container about the total matches of a find
// request.
virtual void ReportFindInPageMatchCount(int identifier,
@@ -107,6 +114,9 @@ class PdfViewWebPlugin final : public PdfViewPluginBase,
// Notifies the frame widget about the selection bound change.
virtual void UpdateSelectionBounds() = 0;
+ // Gets the embedder's origin as a serialized string.
+ virtual std::string GetEmbedderOriginString() = 0;
+
// Returns the local frame to which the web plugin container belongs.
virtual blink::WebLocalFrame* GetFrame() = 0;
@@ -193,20 +203,31 @@ class PdfViewWebPlugin final : public PdfViewPluginBase,
void StopFind() override;
bool CanRotateView() override;
void RotateView(blink::WebPlugin::RotationType type) override;
+
+ bool ShouldDispatchImeEventsToPlugin() override;
blink::WebTextInputType GetPluginTextInputType() override;
+ gfx::Rect GetPluginCaretBounds() override;
+ void ImeSetCompositionForPlugin(
+ const blink::WebString& text,
+ const std::vector<ui::ImeTextSpan>& ime_text_spans,
+ const gfx::Range& replacement_range,
+ int selection_start,
+ int selection_end) override;
+ void ImeCommitTextForPlugin(
+ const blink::WebString& text,
+ const std::vector<ui::ImeTextSpan>& ime_text_spans,
+ const gfx::Range& replacement_range,
+ int relative_cursor_pos) override;
+ void ImeFinishComposingTextForPlugin(bool keep_selection) override;
// PdfViewPluginBase:
void UpdateCursor(ui::mojom::CursorType new_cursor_type) override;
- void UpdateTickMarks(const std::vector<gfx::Rect>& tickmarks) override;
- void NotifyNumberOfFindResultsChanged(int total, bool final_result) override;
void NotifySelectedFindResultChanged(int current_find_index) override;
+ void CaretChanged(const gfx::Rect& caret_rect) override;
void Alert(const std::string& message) override;
bool Confirm(const std::string& message) override;
std::string Prompt(const std::string& question,
const std::string& default_answer) override;
- void SubmitForm(const std::string& url,
- const void* data,
- int length) override;
std::vector<SearchStringResult> SearchString(const char16_t* string,
const char16_t* term,
bool case_sensitive) override;
@@ -235,20 +256,23 @@ class PdfViewWebPlugin final : public PdfViewPluginBase,
void UpdateSnapshot(sk_sp<SkImage> snapshot) override;
// PdfAccessibilityActionHandler:
+ void EnableAccessibility() override;
void HandleAccessibilityAction(
const AccessibilityActionData& action_data) override;
- // Initializes the plugin using the `container_wrapper` provided by tests.
- bool InitializeForTesting(
- std::unique_ptr<ContainerWrapper> container_wrapper);
+ // Initializes the plugin using the `container_wrapper` and `engine` provided
+ // by tests.
+ bool InitializeForTesting(std::unique_ptr<ContainerWrapper> container_wrapper,
+ std::unique_ptr<PDFiumEngine> engine);
const gfx::Rect& GetPluginRectForTesting() const { return plugin_rect(); }
+ float GetDeviceScaleForTesting() const { return device_scale(); }
+
protected:
// PdfViewPluginBase:
base::WeakPtr<PdfViewPluginBase> GetWeakPtr() override;
std::unique_ptr<UrlLoader> CreateUrlLoaderInternal() override;
- void DidOpen(std::unique_ptr<UrlLoader> loader, int32_t result) override;
void SendMessage(base::Value message) override;
void SaveAs() override;
void InitImageData(const gfx::Size& size) override;
@@ -260,6 +284,8 @@ class PdfViewWebPlugin final : public PdfViewPluginBase,
AccessibilityPageObjects page_objects) override;
void SetAccessibilityViewportInfo(
const AccessibilityViewportInfo& viewport_info) override;
+ void NotifyFindResultsChanged(int total, bool final_result) override;
+ void NotifyFindTickmarks(const std::vector<gfx::Rect>& tickmarks) override;
void SetContentRestrictions(int content_restrictions) override;
void SetPluginCanSave(bool can_save) override;
void PluginDidStartLoading() override;
@@ -276,9 +302,11 @@ class PdfViewWebPlugin final : public PdfViewPluginBase,
// Call `Destroy()` instead.
~PdfViewWebPlugin() override;
- bool InitializeCommon(std::unique_ptr<ContainerWrapper> container_wrapper);
+ bool InitializeCommon(std::unique_ptr<ContainerWrapper> container_wrapper,
+ std::unique_ptr<PDFiumEngine> engine);
- void OnViewportChanged(const gfx::Rect& view_rect, float new_device_scale);
+ void OnViewportChanged(const gfx::Rect& plugin_rect_in_css_pixel,
+ float new_device_scale);
// Invalidates the entire web plugin container and schedules a paint of the
// page in it.
@@ -291,6 +319,10 @@ class PdfViewWebPlugin final : public PdfViewPluginBase,
bool Undo();
bool Redo();
+ // Helper method for converting IME text to input events.
+ // TODO(crbug.com/1253665): Consider handling composition events.
+ void HandleImeCommit(const blink::WebString& text);
+
// Callback to print without re-entrancy issues. The callback prevents the
// invocation of printing in the middle of an event handler, which is risky;
// see crbug.com/66334.
@@ -298,6 +330,11 @@ class PdfViewWebPlugin final : public PdfViewPluginBase,
// the plugin are moved off the main thread.
void OnInvokePrintDialog(int32_t /*result*/);
+ // Callback to set the viewport information in accessibility tree
+ // asynchronously.
+ void OnSetAccessibilityViewportInfo(
+ const AccessibilityViewportInfo& viewport_info);
+
// May be null in unit tests.
pdf::mojom::PdfService* GetPdfService();
@@ -305,9 +342,13 @@ class PdfViewWebPlugin final : public PdfViewPluginBase,
std::unique_ptr<Client> const client_;
+ // Used to access the services provided by the browser.
// May be unbound in unit tests.
mojo::AssociatedRemote<pdf::mojom::PdfService> const pdf_service_remote_;
+ // Used to access find-in-page interface provided by the PDF extension.
+ mojo::Remote<pdf::mojom::PdfFindInPage> find_remote_;
+
// The id of the current find operation, or -1 if no current operation is
// present.
int find_identifier_ = -1;
@@ -315,6 +356,10 @@ class PdfViewWebPlugin final : public PdfViewPluginBase,
blink::WebTextInputType text_input_type_ =
blink::WebTextInputType::kWebTextInputTypeNone;
+ gfx::Rect caret_rect_;
+
+ blink::WebString composition_text_;
+
// Whether the plugin element currently has focus.
bool has_focus_ = false;
@@ -330,6 +375,12 @@ class PdfViewWebPlugin final : public PdfViewPluginBase,
// The viewport coordinates to DIP (device-independent pixel) ratio.
float viewport_to_dip_scale_ = 1.0f;
+ // The device pixel to CSS pixel ratio.
+ float device_to_css_scale_ = 1.0f;
+
+ // The plugin rect in CSS pixels.
+ gfx::Rect css_plugin_rect_;
+
// May be null in unit tests.
std::unique_ptr<PdfAccessibilityDataHandler> const
pdf_accessibility_data_handler_;
diff --git a/chromium/pdf/pdf_view_web_plugin_unittest.cc b/chromium/pdf/pdf_view_web_plugin_unittest.cc
index b5046a32119..0d39071a88a 100644
--- a/chromium/pdf/pdf_view_web_plugin_unittest.cc
+++ b/chromium/pdf/pdf_view_web_plugin_unittest.cc
@@ -5,27 +5,42 @@
#include "pdf/pdf_view_web_plugin.h"
#include <memory>
+#include <string>
#include <utility>
+#include "base/strings/string_piece.h"
#include "cc/paint/paint_canvas.h"
#include "cc/test/pixel_comparator.h"
#include "cc/test/pixel_test_utils.h"
#include "pdf/ppapi_migration/bitmap.h"
#include "pdf/test/test_helpers.h"
+#include "pdf/test/test_pdfium_engine.h"
#include "testing/gmock/include/gmock/gmock-matchers.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/common/input/web_coalesced_input_event.h"
+#include "third_party/blink/public/common/input/web_input_event.h"
+#include "third_party/blink/public/common/input/web_keyboard_event.h"
+#include "third_party/blink/public/common/input/web_mouse_event.h"
+#include "third_party/blink/public/common/input/web_pointer_properties.h"
#include "third_party/blink/public/platform/web_string.h"
#include "third_party/blink/public/platform/web_text_input_type.h"
#include "third_party/blink/public/platform/web_vector.h"
#include "third_party/blink/public/web/web_associated_url_loader.h"
+#include "third_party/blink/public/web/web_plugin_container.h"
#include "third_party/blink/public/web/web_plugin_params.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/skia/include/core/SkColor.h"
+#include "ui/base/cursor/cursor.h"
+#include "ui/events/blink/blink_event_util.h"
+#include "ui/events/keycodes/dom/dom_code.h"
+#include "ui/events/keycodes/dom/dom_key.h"
#include "ui/gfx/canvas.h"
+#include "ui/gfx/geometry/point_f.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/size.h"
-#include "ui/gfx/skia_util.h"
+#include "ui/gfx/geometry/skia_conversions.h"
+#include "ui/latency/latency_info.h"
namespace chrome_pdf {
@@ -42,6 +57,9 @@ using ::testing::Return;
// testing.
constexpr gfx::Size kCanvasSize(100, 100);
+// A common device scale for high DPI displays.
+constexpr float kDeviceScale = 2.0f;
+
// Note: Make sure `kDefaultColor` is different from `kPaintColor` and the
// plugin's background color. This will help identify bitmap changes after
// painting.
@@ -53,11 +71,15 @@ struct PaintParams {
// The plugin container's device scale.
float device_scale;
- // The window area.
+ // The window area in CSS pixels.
gfx::Rect window_rect;
- // The target painting area on the canvas.
+ // The target painting area on the canvas in CSS pixels.
gfx::Rect paint_rect;
+
+ // The expected clipped area to be filled with paint color. The clipped area
+ // should be the intersection of `paint_rect` and `window_rect`.
+ gfx::Rect expected_clipped_rect;
};
MATCHER(SearchStringResultEq, "") {
@@ -66,26 +88,44 @@ MATCHER(SearchStringResultEq, "") {
return l.start_index == r.start_index && l.length == r.length;
}
+MATCHER_P(IsExpectedImeKeyEvent, expected_text, "") {
+ if (arg.GetType() != blink::WebInputEvent::Type::kChar)
+ return false;
+
+ const auto& event = static_cast<const blink::WebKeyboardEvent&>(arg);
+ return event.GetModifiers() == blink::WebInputEvent::kNoModifiers &&
+ event.windows_key_code == expected_text[0] &&
+ event.native_key_code == expected_text[0] &&
+ event.dom_code == static_cast<int>(ui::DomCode::NONE) &&
+ event.dom_key == ui::DomKey::NONE && !event.is_system_key &&
+ !event.is_browser_shortcut && event.text == expected_text &&
+ event.unmodified_text == expected_text;
+}
+
// Generates the expected `SkBitmap` with `paint_color` filled in the expected
// clipped area and `kDefaultColor` as the background color.
-SkBitmap GenerateExpectedBitmapForPaint(float device_scale,
- bool use_zoom_for_dsf,
- const gfx::Rect& plugin_rect,
- const gfx::Rect& paint_rect,
+SkBitmap GenerateExpectedBitmapForPaint(const gfx::Rect& expected_clipped_rect,
SkColor paint_color) {
- float inverse_scale = use_zoom_for_dsf ? 1.0f : 1.0f / device_scale;
- // TODO(crbug.com/1238395): Improve the test by pre-define the
- // `expected_clipped_area` instead of calculating it inside the test.
- gfx::Rect expected_clipped_area = gfx::IntersectRects(
- gfx::ScaleToEnclosingRectSafe(plugin_rect, inverse_scale), paint_rect);
SkBitmap expected_bitmap =
CreateN32PremulSkBitmap(gfx::SizeToSkISize(kCanvasSize));
expected_bitmap.eraseColor(kDefaultColor);
- expected_bitmap.erase(paint_color, gfx::RectToSkIRect(expected_clipped_area));
+ expected_bitmap.erase(paint_color, gfx::RectToSkIRect(expected_clipped_rect));
return expected_bitmap;
}
-class FakeContainerWrapper final : public PdfViewWebPlugin::ContainerWrapper {
+blink::WebMouseEvent CreateDefaultMouseDownEvent() {
+ blink::WebMouseEvent web_event(
+ blink::WebInputEvent::Type::kMouseDown,
+ /*position=*/gfx::PointF(),
+ /*global_position=*/gfx::PointF(),
+ blink::WebPointerProperties::Button::kLeft,
+ /*click_count_param=*/1, blink::WebInputEvent::Modifiers::kLeftButtonDown,
+ blink::WebInputEvent::GetStaticTimeStampForTests());
+ web_event.SetFrameScale(1);
+ return web_event;
+}
+
+class FakeContainerWrapper : public PdfViewWebPlugin::ContainerWrapper {
public:
explicit FakeContainerWrapper(PdfViewWebPlugin* web_plugin)
: web_plugin_(web_plugin) {
@@ -103,6 +143,11 @@ class FakeContainerWrapper final : public PdfViewWebPlugin::ContainerWrapper {
// PdfViewWebPlugin::ContainerWrapper:
void Invalidate() override {}
+ MOCK_METHOD(void,
+ RequestTouchEventType,
+ (blink::WebPluginContainer::TouchEventRequestType),
+ (override));
+
MOCK_METHOD(void, ReportFindInPageMatchCount, (int, int, bool), (override));
MOCK_METHOD(void, ReportFindInPageSelection, (int, int), (override));
@@ -137,6 +182,10 @@ class FakeContainerWrapper final : public PdfViewWebPlugin::ContainerWrapper {
MOCK_METHOD(void, UpdateSelectionBounds, (), (override));
+ std::string GetEmbedderOriginString() override {
+ return "chrome-extension://mhjfbmdgcfjbbpaeojofohoefgiehjai/";
+ }
+
blink::WebLocalFrame* GetFrame() override { return nullptr; }
blink::WebLocalFrameClient* GetWebLocalFrameClient() override {
@@ -182,18 +231,22 @@ class FakePdfViewWebPluginClient : public PdfViewWebPlugin::Client {
} // namespace
-class PdfViewWebPluginTest : public testing::Test {
+class PdfViewWebPluginWithoutInitializeTest : public testing::Test {
public:
+ PdfViewWebPluginWithoutInitializeTest(
+ const PdfViewWebPluginWithoutInitializeTest&) = delete;
+ PdfViewWebPluginWithoutInitializeTest& operator=(
+ const PdfViewWebPluginWithoutInitializeTest&) = delete;
+
+ protected:
// Custom deleter for `plugin_`. PdfViewWebPlugin must be destroyed by
// PdfViewWebPlugin::Destroy() instead of its destructor.
struct PluginDeleter {
void operator()(PdfViewWebPlugin* ptr) { ptr->Destroy(); }
};
- PdfViewWebPluginTest() = default;
- PdfViewWebPluginTest(const PdfViewWebPluginTest&) = delete;
- PdfViewWebPluginTest& operator=(const PdfViewWebPluginTest&) = delete;
- ~PdfViewWebPluginTest() override = default;
+ PdfViewWebPluginWithoutInitializeTest() = default;
+ ~PdfViewWebPluginWithoutInitializeTest() override = default;
void SetUp() override {
// Set a dummy URL for initializing the plugin.
@@ -208,15 +261,37 @@ class PdfViewWebPluginTest : public testing::Test {
plugin_ =
std::unique_ptr<PdfViewWebPlugin, PluginDeleter>(new PdfViewWebPlugin(
std::move(client), std::move(unbound_remote), params));
+ }
+
+ void TearDown() override { plugin_.reset(); }
- auto wrapper = std::make_unique<FakeContainerWrapper>(plugin_.get());
+ FakePdfViewWebPluginClient* client_ptr_;
+ std::unique_ptr<PdfViewWebPlugin, PluginDeleter> plugin_;
+};
+
+class PdfViewWebPluginTest : public PdfViewWebPluginWithoutInitializeTest {
+ protected:
+ void SetUp() override {
+ PdfViewWebPluginWithoutInitializeTest::SetUp();
+
+ auto wrapper =
+ std::make_unique<NiceMock<FakeContainerWrapper>>(plugin_.get());
wrapper_ptr_ = wrapper.get();
- plugin_->InitializeForTesting(std::move(wrapper));
+ auto engine = CreateEngine();
+ engine_ptr_ = engine.get();
+ EXPECT_TRUE(
+ plugin_->InitializeForTesting(std::move(wrapper), std::move(engine)));
}
void TearDown() override {
- plugin_.reset();
wrapper_ptr_ = nullptr;
+
+ PdfViewWebPluginWithoutInitializeTest::TearDown();
+ }
+
+ // Allow derived test classes to create their own custom TestPDFiumEngine.
+ virtual std::unique_ptr<TestPDFiumEngine> CreateEngine() {
+ return std::make_unique<TestPDFiumEngine>(plugin_.get());
}
void UpdatePluginGeometry(float device_scale, const gfx::Rect& window_rect) {
@@ -230,19 +305,21 @@ class PdfViewWebPluginTest : public testing::Test {
void TestUpdateGeometrySetsPluginRect(float device_scale,
const gfx::Rect& window_rect,
+ float expected_device_scale,
const gfx::Rect& expected_plugin_rect) {
UpdatePluginGeometry(device_scale, window_rect);
+ EXPECT_EQ(expected_device_scale, plugin_->GetDeviceScaleForTesting())
+ << "Device scale comparison failure at device scale of "
+ << device_scale;
EXPECT_EQ(expected_plugin_rect, plugin_->GetPluginRectForTesting())
- << "Failure at device scale of " << device_scale << ", window rect of "
- << window_rect.ToString();
+ << "Plugin rect comparison failure at device scale of " << device_scale
+ << ", window rect of " << window_rect.ToString();
}
void TestPaintEmptySnapshots(float device_scale,
- bool use_zoom_for_dsf,
const gfx::Rect& window_rect,
- const gfx::Rect& paint_rect) {
- EXPECT_CALL(*client_ptr_, IsUseZoomForDSFEnabled)
- .WillOnce(Return(use_zoom_for_dsf));
+ const gfx::Rect& paint_rect,
+ const gfx::Rect& expected_clipped_rect) {
UpdatePluginGeometry(device_scale, window_rect);
canvas_.DrawColor(kDefaultColor);
@@ -251,8 +328,7 @@ class PdfViewWebPluginTest : public testing::Test {
// Expect the clipped area on canvas to be filled with plugin's background
// color.
SkBitmap expected_bitmap = GenerateExpectedBitmapForPaint(
- device_scale, use_zoom_for_dsf, plugin_->GetPluginRectForTesting(),
- paint_rect, plugin_->GetBackgroundColor());
+ expected_clipped_rect, plugin_->GetBackgroundColor());
EXPECT_TRUE(
cc::MatchesBitmap(canvas_.GetBitmap(), expected_bitmap,
cc::ExactPixelComparator(/*discard_alpha=*/false)))
@@ -261,11 +337,9 @@ class PdfViewWebPluginTest : public testing::Test {
}
void TestPaintSnapshots(float device_scale,
- bool use_zoom_for_dsf,
const gfx::Rect& window_rect,
- const gfx::Rect& paint_rect) {
- EXPECT_CALL(*client_ptr_, IsUseZoomForDSFEnabled)
- .WillOnce(Return(use_zoom_for_dsf));
+ const gfx::Rect& paint_rect,
+ const gfx::Rect& expected_clipped_rect) {
UpdatePluginGeometry(device_scale, window_rect);
canvas_.DrawColor(kDefaultColor);
@@ -282,8 +356,8 @@ class PdfViewWebPluginTest : public testing::Test {
plugin_->Paint(canvas_.sk_canvas(), paint_rect);
// Expect the clipped area on canvas to be filled with `kPaintColor`.
- SkBitmap expected_bitmap = GenerateExpectedBitmapForPaint(
- device_scale, use_zoom_for_dsf, plugin_rect, paint_rect, kPaintColor);
+ SkBitmap expected_bitmap =
+ GenerateExpectedBitmapForPaint(expected_clipped_rect, kPaintColor);
EXPECT_TRUE(
cc::MatchesBitmap(canvas_.GetBitmap(), expected_bitmap,
cc::ExactPixelComparator(/*discard_alpha=*/false)))
@@ -291,30 +365,44 @@ class PdfViewWebPluginTest : public testing::Test {
<< window_rect.ToString();
}
+ TestPDFiumEngine* engine_ptr_;
FakeContainerWrapper* wrapper_ptr_;
- FakePdfViewWebPluginClient* client_ptr_;
- std::unique_ptr<PdfViewWebPlugin, PluginDeleter> plugin_;
// Provides the cc::PaintCanvas for painting.
gfx::Canvas canvas_{kCanvasSize, /*image_scale=*/1.0f, /*is_opaque=*/true};
};
-// TODO(crbug.com/1238395): Split this test into two: One with zoom-for-DSF
-// enabled, one with zoom-for-DSF disabled.
-TEST_F(PdfViewWebPluginTest,
- UpdateGeometrySetsPluginRectOnDifferentUseZoomForDSFSettings) {
- // Use the same device scale for this test.
- const float device_scale = 2.0f;
+TEST_F(PdfViewWebPluginWithoutInitializeTest, Initialize) {
+ auto wrapper =
+ std::make_unique<NiceMock<FakeContainerWrapper>>(plugin_.get());
+ auto engine = std::make_unique<TestPDFiumEngine>(plugin_.get());
+ EXPECT_CALL(*wrapper,
+ RequestTouchEventType(
+ blink::WebPluginContainer::kTouchEventRequestTypeRaw));
- // Test when using zoom for DSF is enabled.
- EXPECT_CALL(*client_ptr_, IsUseZoomForDSFEnabled).WillOnce(Return(true));
- TestUpdateGeometrySetsPluginRect(device_scale, gfx::Rect(4, 4, 12, 12),
- gfx::Rect(4, 4, 12, 12));
+ EXPECT_TRUE(
+ plugin_->InitializeForTesting(std::move(wrapper), std::move(engine)));
+}
- // Test when using zoom for DSF is disabled.
- EXPECT_CALL(*client_ptr_, IsUseZoomForDSFEnabled).WillOnce(Return(false));
- TestUpdateGeometrySetsPluginRect(device_scale, gfx::Rect(4, 4, 12, 12),
- gfx::Rect(8, 8, 24, 24));
+TEST_F(PdfViewWebPluginTest, UpdateGeometrySetsPluginRectUseZoomForDSFEnabled) {
+ EXPECT_CALL(*client_ptr_, IsUseZoomForDSFEnabled)
+ .WillRepeatedly(Return(true));
+ EXPECT_CALL(*engine_ptr_, ZoomUpdated(2.0f));
+ TestUpdateGeometrySetsPluginRect(
+ /*device_scale=*/2.0f, /*window_rect=*/gfx::Rect(4, 4, 12, 12),
+ /*expected_device_scale=*/2.0f,
+ /*expected_plugin_rect=*/gfx::Rect(4, 4, 12, 12));
+}
+
+TEST_F(PdfViewWebPluginTest,
+ UpdateGeometrySetsPluginRectUseZoomForDSFDisabled) {
+ EXPECT_CALL(*client_ptr_, IsUseZoomForDSFEnabled)
+ .WillRepeatedly(Return(false));
+ EXPECT_CALL(*engine_ptr_, ZoomUpdated(2.0f));
+ TestUpdateGeometrySetsPluginRect(
+ /*device_scale=*/2.0f, /*window_rect=*/gfx::Rect(4, 4, 12, 12),
+ /*expected_device_scale=*/2.0f,
+ /*expected_plugin_rect=*/gfx::Rect(8, 8, 24, 24));
}
TEST_F(PdfViewWebPluginTest,
@@ -323,9 +411,12 @@ TEST_F(PdfViewWebPluginTest,
// The plugin container's device scale.
float device_scale;
- // The window rect in device pixels.
+ // The window rect in CSS pixels.
gfx::Rect window_rect;
+ // The expected plugin device scale.
+ float expected_device_scale;
+
// The expected plugin rect in device pixels.
gfx::Rect expected_plugin_rect;
};
@@ -335,51 +426,261 @@ TEST_F(PdfViewWebPluginTest,
.WillRepeatedly(Return(true));
static constexpr UpdateGeometryParams kUpdateGeometryParams[] = {
- {1.0f, gfx::Rect(3, 4, 5, 6), gfx::Rect(3, 4, 5, 6)},
- {2.0f, gfx::Rect(4, 4, 12, 12), gfx::Rect(4, 4, 12, 12)},
- {2.0f, gfx::Rect(5, 6, 7, 8), gfx::Rect(4, 6, 8, 8)},
+ {1.0f, gfx::Rect(3, 4, 5, 6), 1.0f, gfx::Rect(3, 4, 5, 6)},
+ {2.0f, gfx::Rect(3, 4, 5, 6), 2.0f, gfx::Rect(3, 4, 5, 6)},
};
for (const auto& params : kUpdateGeometryParams) {
TestUpdateGeometrySetsPluginRect(params.device_scale, params.window_rect,
+ params.expected_device_scale,
params.expected_plugin_rect);
}
}
-TEST_F(PdfViewWebPluginTest, PaintEmptySnapshots) {
- static constexpr PaintParams kPaintEmptySnapshotsParams[]{
- // The window origin falls outside the `paint_rect` area.
- {1.0f, gfx::Rect(10, 10, 20, 20), gfx::Rect(5, 5, 15, 15)},
- {4.0f, gfx::Rect(10, 10, 20, 20), gfx::Rect(5, 5, 15, 15)},
- // The window origin falls within the `paint_rect` area.
- {1.0f, gfx::Rect(4, 4, 20, 20), gfx::Rect(8, 8, 15, 15)},
- {4.0f, gfx::Rect(4, 4, 20, 20), gfx::Rect(8, 8, 15, 15)},
+class PdfViewWebPluginTestUseZoomForDSF
+ : public PdfViewWebPluginTest,
+ public testing::WithParamInterface<bool> {
+ public:
+ void SetUp() override {
+ PdfViewWebPluginTest::SetUp();
+ ON_CALL(*client_ptr_, IsUseZoomForDSFEnabled)
+ .WillByDefault(Return(GetParam()));
+ }
+};
+
+TEST_P(PdfViewWebPluginTestUseZoomForDSF,
+ UpdateGeometrySetsPluginRectWithEmptyWindow) {
+ EXPECT_CALL(*engine_ptr_, ZoomUpdated).Times(0);
+ TestUpdateGeometrySetsPluginRect(
+ /*device_scale=*/2.0f, /*window_rect=*/gfx::Rect(2, 2, 0, 0),
+ /*expected_device_scale=*/1.0f, /*expected_plugin_rect=*/gfx::Rect());
+}
+
+TEST_P(PdfViewWebPluginTestUseZoomForDSF, PaintEmptySnapshots) {
+ TestPaintEmptySnapshots(/*device_scale=*/4.0f,
+ /*window_rect=*/gfx::Rect(10, 10, 20, 20),
+ /*paint_rect=*/gfx::Rect(5, 5, 15, 15),
+ /*expected_clipped_rect=*/gfx::Rect(10, 10, 10, 10));
+}
+
+TEST_P(PdfViewWebPluginTestUseZoomForDSF, PaintSnapshots) {
+ TestPaintSnapshots(/*device_scale=*/4.0f,
+ /*window_rect=*/gfx::Rect(10, 10, 20, 20),
+ /*paint_rect=*/gfx::Rect(5, 5, 15, 15),
+ /*expected_clipped_rect=*/gfx::Rect(10, 10, 10, 10));
+}
+
+TEST_P(PdfViewWebPluginTestUseZoomForDSF,
+ PaintSnapshotsWithVariousDeviceScales) {
+ static constexpr PaintParams kPaintWithVariousScalesParams[] = {
+ {0.4f, gfx::Rect(8, 8, 30, 30), gfx::Rect(10, 10, 30, 30),
+ gfx::Rect(10, 10, 28, 28)},
+ {1.0f, gfx::Rect(8, 8, 30, 30), gfx::Rect(10, 10, 30, 30),
+ gfx::Rect(10, 10, 28, 28)},
+ {4.0f, gfx::Rect(8, 8, 30, 30), gfx::Rect(10, 10, 30, 30),
+ gfx::Rect(10, 10, 28, 28)},
};
- for (const auto& params : kPaintEmptySnapshotsParams) {
- TestPaintEmptySnapshots(params.device_scale, /*use_zoom_for_dsf=*/true,
- params.window_rect, params.paint_rect);
- TestPaintEmptySnapshots(params.device_scale, /*use_zoom_for_dsf=*/false,
- params.window_rect, params.paint_rect);
+ for (const auto& params : kPaintWithVariousScalesParams) {
+ TestPaintSnapshots(params.device_scale, params.window_rect,
+ params.paint_rect, params.expected_clipped_rect);
}
}
-TEST_F(PdfViewWebPluginTest, PaintSnapshots) {
- static constexpr PaintParams kPaintWithScalesTestParams[] = {
+TEST_P(PdfViewWebPluginTestUseZoomForDSF,
+ PaintSnapshotsWithVariousRectPositions) {
+ static constexpr PaintParams kPaintWithVariousPositionsParams[] = {
// The window origin falls outside the `paint_rect` area.
- {1.0f, gfx::Rect(8, 8, 30, 30), gfx::Rect(10, 10, 30, 30)},
- {2.0f, gfx::Rect(8, 8, 30, 30), gfx::Rect(10, 10, 30, 30)},
+ {4.0f, gfx::Rect(10, 10, 20, 20), gfx::Rect(5, 5, 15, 15),
+ gfx::Rect(10, 10, 10, 10)},
// The window origin falls within the `paint_rect` area.
- {1.0f, gfx::Rect(10, 10, 30, 30), gfx::Rect(4, 4, 30, 30)},
- {2.0f, gfx::Rect(10, 10, 30, 30), gfx::Rect(4, 4, 30, 30)},
+ {4.0f, gfx::Rect(4, 4, 20, 20), gfx::Rect(8, 8, 15, 15),
+ gfx::Rect(8, 8, 15, 15)},
+ };
+
+ for (const auto& params : kPaintWithVariousPositionsParams) {
+ TestPaintSnapshots(params.device_scale, params.window_rect,
+ params.paint_rect, params.expected_clipped_rect);
+ }
+}
+
+INSTANTIATE_TEST_SUITE_P(All,
+ PdfViewWebPluginTestUseZoomForDSF,
+ testing::Bool());
+
+class PdfViewWebPluginMouseEventsTest : public PdfViewWebPluginTest {
+ public:
+ class TestPDFiumEngineForMouseEvents : public TestPDFiumEngine {
+ public:
+ explicit TestPDFiumEngineForMouseEvents(PDFEngine::Client* client)
+ : TestPDFiumEngine(client) {}
+
+ // TestPDFiumEngine:
+ bool HandleInputEvent(const blink::WebInputEvent& event) override {
+ // Since blink::WebInputEvent is an abstract class, we cannot use equal
+ // matcher to verify its value. Here we test with blink::WebMouseEvent
+ // specifically.
+ if (!blink::WebInputEvent::IsMouseEventType(event.GetType()))
+ return false;
+
+ scaled_mouse_event_ = std::make_unique<blink::WebMouseEvent>();
+ *scaled_mouse_event_ = static_cast<const blink::WebMouseEvent&>(event);
+ return true;
+ }
+
+ const blink::WebMouseEvent* GetScaledMouseEvent() const {
+ return scaled_mouse_event_.get();
+ }
+
+ private:
+ std::unique_ptr<blink::WebMouseEvent> scaled_mouse_event_;
};
- for (const auto& params : kPaintWithScalesTestParams) {
- TestPaintSnapshots(params.device_scale, /*use_zoom_for_dsf=*/true,
- params.window_rect, params.paint_rect);
- TestPaintSnapshots(params.device_scale, /*use_zoom_for_dsf=*/false,
- params.window_rect, params.paint_rect);
+ std::unique_ptr<TestPDFiumEngine> CreateEngine() override {
+ return std::make_unique<TestPDFiumEngineForMouseEvents>(plugin_.get());
+ }
+
+ TestPDFiumEngineForMouseEvents* engine() {
+ return static_cast<TestPDFiumEngineForMouseEvents*>(engine_ptr_);
+ }
+};
+
+TEST_F(PdfViewWebPluginMouseEventsTest,
+ HandleInputEventWithUseZoomForDSFEnabled) {
+ // Test when using zoom for DSF is enabled.
+ EXPECT_CALL(*client_ptr_, IsUseZoomForDSFEnabled)
+ .WillRepeatedly(Return(true));
+ wrapper_ptr_->set_device_scale(kDeviceScale);
+ UpdatePluginGeometry(kDeviceScale, gfx::Rect(20, 20));
+
+ ui::Cursor dummy_cursor;
+ plugin_->HandleInputEvent(
+ blink::WebCoalescedInputEvent(CreateDefaultMouseDownEvent(),
+ ui::LatencyInfo()),
+ &dummy_cursor);
+
+ const blink::WebMouseEvent* event = engine()->GetScaledMouseEvent();
+ ASSERT_TRUE(event);
+ EXPECT_EQ(gfx::PointF(-10.0f, 0.0f), event->PositionInWidget());
+}
+
+TEST_F(PdfViewWebPluginMouseEventsTest,
+ HandleInputEventWithUseZoomForDSFDisabled) {
+ // Test when using zoom for DSF is disabled.
+ EXPECT_CALL(*client_ptr_, IsUseZoomForDSFEnabled)
+ .WillRepeatedly(Return(false));
+ wrapper_ptr_->set_device_scale(kDeviceScale);
+ UpdatePluginGeometry(kDeviceScale, gfx::Rect(20, 20));
+
+ ui::Cursor dummy_cursor;
+ plugin_->HandleInputEvent(
+ blink::WebCoalescedInputEvent(CreateDefaultMouseDownEvent(),
+ ui::LatencyInfo()),
+ &dummy_cursor);
+
+ const blink::WebMouseEvent* event = engine()->GetScaledMouseEvent();
+ ASSERT_TRUE(event);
+ EXPECT_EQ(gfx::PointF(-20.0f, 0.0f), event->PositionInWidget());
+}
+
+class PdfViewWebPluginImeTest : public PdfViewWebPluginTest {
+ public:
+ class TestPDFiumEngineForIme : public TestPDFiumEngine {
+ public:
+ explicit TestPDFiumEngineForIme(PDFEngine::Client* client)
+ : TestPDFiumEngine(client) {}
+
+ // TestPDFiumEngine:
+ MOCK_METHOD(bool,
+ HandleInputEvent,
+ (const blink::WebInputEvent&),
+ (override));
+ };
+
+ std::unique_ptr<TestPDFiumEngine> CreateEngine() override {
+ return std::make_unique<TestPDFiumEngineForIme>(plugin_.get());
+ }
+
+ TestPDFiumEngineForIme* engine() {
+ return static_cast<TestPDFiumEngineForIme*>(engine_ptr_);
+ }
+
+ void TestImeSetCompositionForPlugin(const blink::WebString& text) {
+ EXPECT_CALL(*engine(), HandleInputEvent).Times(0);
+ plugin_->ImeSetCompositionForPlugin(text, std::vector<ui::ImeTextSpan>(),
+ gfx::Range(),
+ /*selection_start=*/0,
+ /*selection_end=*/0);
}
+
+ void TestImeFinishComposingTextForPlugin(
+ const blink::WebString& expected_text) {
+ InSequence sequence;
+ std::u16string expected_text16 = expected_text.Utf16();
+ if (expected_text16.size()) {
+ for (const auto& c : expected_text16) {
+ base::StringPiece16 expected_key(&c, 1);
+ EXPECT_CALL(*engine(),
+ HandleInputEvent(IsExpectedImeKeyEvent(expected_key)))
+ .WillOnce(Return(true));
+ }
+ } else {
+ EXPECT_CALL(*engine(), HandleInputEvent).Times(0);
+ }
+ plugin_->ImeFinishComposingTextForPlugin(false);
+ }
+
+ void TestImeCommitTextForPlugin(const blink::WebString& text) {
+ InSequence sequence;
+ std::u16string expected_text16 = text.Utf16();
+ if (expected_text16.size()) {
+ for (const auto& c : expected_text16) {
+ base::StringPiece16 event(&c, 1);
+ EXPECT_CALL(*engine(), HandleInputEvent(IsExpectedImeKeyEvent(event)))
+ .WillOnce(Return(true));
+ }
+ } else {
+ EXPECT_CALL(*engine(), HandleInputEvent).Times(0);
+ }
+ plugin_->ImeCommitTextForPlugin(text, std::vector<ui::ImeTextSpan>(),
+ gfx::Range(),
+ /*relative_cursor_pos=*/0);
+ }
+};
+
+TEST_F(PdfViewWebPluginImeTest, ImeSetCompositionAndFinishAscii) {
+ const blink::WebString text = blink::WebString::FromASCII("input");
+ TestImeSetCompositionForPlugin(text);
+ TestImeFinishComposingTextForPlugin(text);
+}
+
+TEST_F(PdfViewWebPluginImeTest, ImeSetCompositionAndFinishUnicode) {
+ const blink::WebString text = blink::WebString::FromUTF16(u"你好");
+ TestImeSetCompositionForPlugin(text);
+ TestImeFinishComposingTextForPlugin(text);
+ // Calling ImeFinishComposingTextForPlugin() again is a no-op.
+ TestImeFinishComposingTextForPlugin("");
+}
+
+TEST_F(PdfViewWebPluginImeTest, ImeSetCompositionAndFinishEmpty) {
+ const blink::WebString text;
+ TestImeSetCompositionForPlugin(text);
+ TestImeFinishComposingTextForPlugin(text);
+}
+
+TEST_F(PdfViewWebPluginImeTest, ImeCommitTextForPluginAscii) {
+ const blink::WebString text = blink::WebString::FromASCII("a b");
+ TestImeCommitTextForPlugin(text);
+}
+
+TEST_F(PdfViewWebPluginImeTest, ImeCommitTextForPluginUnicode) {
+ const blink::WebString text = blink::WebString::FromUTF16(u"さようなら");
+ TestImeCommitTextForPlugin(text);
+}
+
+TEST_F(PdfViewWebPluginImeTest, ImeCommitTextForPluginEmpty) {
+ const blink::WebString text;
+ TestImeCommitTextForPlugin(text);
}
TEST_F(PdfViewWebPluginTest, ChangeTextSelection) {
@@ -492,4 +793,28 @@ TEST_F(PdfViewWebPluginTest, UpdateFocus) {
plugin_->UpdateFocus(/*focused=*/true, blink::mojom::FocusType::kNone);
}
+TEST_F(PdfViewWebPluginTest, ShouldDispatchImeEventsToPlugin) {
+ ASSERT_TRUE(plugin_->ShouldDispatchImeEventsToPlugin());
+}
+
+TEST_F(PdfViewWebPluginTest, CaretChangeUseZoomForDSFEnabled) {
+ EXPECT_CALL(*client_ptr_, IsUseZoomForDSFEnabled)
+ .WillRepeatedly(Return(true));
+ EXPECT_CALL(*engine_ptr_, ZoomUpdated(2.0f));
+ UpdatePluginGeometry(
+ /*device_scale=*/2.0f, /*window_rect=*/gfx::Rect(12, 24, 36, 48));
+ plugin_->CaretChanged(gfx::Rect(10, 20, 30, 40));
+ EXPECT_EQ(gfx::Rect(28, 20, 30, 40), plugin_->GetPluginCaretBounds());
+}
+
+TEST_F(PdfViewWebPluginTest, CaretChangeUseZoomForDSFDisabled) {
+ EXPECT_CALL(*client_ptr_, IsUseZoomForDSFEnabled)
+ .WillRepeatedly(Return(false));
+ EXPECT_CALL(*engine_ptr_, ZoomUpdated(2.0f));
+ UpdatePluginGeometry(
+ /*device_scale=*/2.0f, /*window_rect=*/gfx::Rect(12, 24, 36, 48));
+ plugin_->CaretChanged(gfx::Rect(10, 20, 30, 40));
+ EXPECT_EQ(gfx::Rect(23, 10, 15, 20), plugin_->GetPluginCaretBounds());
+}
+
} // namespace chrome_pdf
diff --git a/chromium/pdf/pdfium/DEPS b/chromium/pdf/pdfium/DEPS
index 248ff0baeea..cdf6a23128c 100644
--- a/chromium/pdf/pdfium/DEPS
+++ b/chromium/pdf/pdfium/DEPS
@@ -2,5 +2,4 @@ include_rules = [
"+components/services/font/public/cpp",
"+third_party/pdfium/public",
"+ui/gfx/codec",
- "+v8/include/cppgc/platform.h",
]
diff --git a/chromium/pdf/pdfium/pdfium_assert_matching_enums.cc b/chromium/pdf/pdfium/pdfium_assert_matching_enums.cc
index fc24ccd4ff5..44e916afe3d 100644
--- a/chromium/pdf/pdfium/pdfium_assert_matching_enums.cc
+++ b/chromium/pdf/pdfium/pdfium_assert_matching_enums.cc
@@ -264,6 +264,8 @@ STATIC_ASSERT_ENUM(kPostScript2, FPDF_PRINTMODE_POSTSCRIPT2);
STATIC_ASSERT_ENUM(kPostScript3, FPDF_PRINTMODE_POSTSCRIPT3);
STATIC_ASSERT_ENUM(kEmfWithReducedRasterization,
FPDF_PRINTMODE_EMF_IMAGE_MASKS);
+STATIC_ASSERT_ENUM(kPostScript3WithType42Fonts,
+ FPDF_PRINTMODE_POSTSCRIPT3_TYPE42);
#endif
} // namespace chrome_pdf
diff --git a/chromium/pdf/pdfium/pdfium_engine.cc b/chromium/pdf/pdfium/pdfium_engine.cc
index 341b183948b..5bdc6bb716e 100644
--- a/chromium/pdf/pdfium/pdfium_engine.cc
+++ b/chromium/pdf/pdfium/pdfium_engine.cc
@@ -25,6 +25,7 @@
#include "base/location.h"
#include "base/notreached.h"
#include "base/stl_util.h"
+#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
@@ -108,8 +109,7 @@ constexpr int32_t kFormHighlightAlpha = 100;
constexpr int kMaxPasswordTries = 3;
-constexpr base::TimeDelta kTouchLongPressTimeout =
- base::TimeDelta::FromMilliseconds(300);
+constexpr base::TimeDelta kTouchLongPressTimeout = base::Milliseconds(300);
// Windows has native panning capabilities. No need to use our own.
#if defined(OS_WIN)
@@ -122,8 +122,7 @@ constexpr int32_t kLoadingTextVerticalOffset = 50;
// The maximum amount of time we'll spend doing a paint before we give back
// control of the thread.
-constexpr base::TimeDelta kMaxProgressivePaintTime =
- base::TimeDelta::FromMilliseconds(300);
+constexpr base::TimeDelta kMaxProgressivePaintTime = base::Milliseconds(300);
// The maximum amount of time we'll spend doing the first paint. This is less
// than the above to keep things smooth if the user is scrolling quickly. This
@@ -137,7 +136,7 @@ constexpr base::TimeDelta kMaxProgressivePaintTime =
// The scrollbar will always be responsive since it is managed by a separate
// process.
constexpr base::TimeDelta kMaxInitialProgressivePaintTime =
- base::TimeDelta::FromMilliseconds(250);
+ base::Milliseconds(250);
FontMappingMode g_font_mapping_mode = FontMappingMode::kNoMapping;
@@ -945,6 +944,10 @@ bool PDFiumEngine::HandleInputEvent(const blink::WebInputEvent& event) {
case blink::WebInputEvent::Type::kMouseEnter:
OnMouseEnter(static_cast<const blink::WebMouseEvent&>(event));
break;
+ case blink::WebInputEvent::Type::kKeyDown:
+ // Blink mostly sends `kRawKeyDown`, but sometimes generates `kKeyDown`,
+ // such as when tabbing between frames. Pepper treats them equivalently
+ // (see content/renderer/pepper/event_conversion.cc), so we will, too.
case blink::WebInputEvent::Type::kRawKeyDown:
rv = OnKeyDown(static_cast<const blink::WebKeyboardEvent&>(event));
break;
@@ -3743,6 +3746,12 @@ void PDFiumEngine::OnSelectionPositionChanged() {
gfx::Size PDFiumEngine::ApplyDocumentLayout(
const DocumentLayout::Options& options) {
+ layout_.SetOptions(options);
+
+ // Don't actually update layout until the document finishes loading.
+ if (!document_loaded_)
+ return layout_.size();
+
// We need to return early if the layout would not change, otherwise calling
// client_->ScrollToPage() would send another "viewport" message, triggering
// an infinite loop.
@@ -3750,7 +3759,6 @@ gfx::Size PDFiumEngine::ApplyDocumentLayout(
// TODO(crbug.com/1013800): The current implementation computes layout twice
// (here, and in InvalidateAllPages()). This shouldn't be too expensive at
// realistic page counts, but could be avoided.
- layout_.SetOptions(options);
UpdateDocumentLayout(&layout_);
if (!layout_.dirty())
return layout_.size();
@@ -4273,7 +4281,7 @@ void PDFiumEngine::SetLinkUnderCursorForAnnotation(FPDF_ANNOTATION annot,
void PDFiumEngine::RequestThumbnail(int page_index,
float device_pixel_ratio,
SendThumbnailCallback send_callback) {
- DCHECK(PageIndexInBounds(page_index));
+ CHECK(PageIndexInBounds(page_index));
// Thumbnails cannot be generated in the middle of a progressive paint of a
// page. Generate the thumbnail immediately only if the page is not currently
diff --git a/chromium/pdf/pdfium/pdfium_engine_unittest.cc b/chromium/pdf/pdfium/pdfium_engine_unittest.cc
index 81116ae81ae..67eb5cbcd89 100644
--- a/chromium/pdf/pdfium/pdfium_engine_unittest.cc
+++ b/chromium/pdf/pdfium/pdfium_engine_unittest.cc
@@ -29,8 +29,10 @@
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/common/input/web_input_event.h"
+#include "third_party/blink/public/common/input/web_keyboard_event.h"
#include "third_party/blink/public/common/input/web_mouse_event.h"
#include "third_party/blink/public/common/input/web_pointer_properties.h"
+#include "ui/events/keycodes/keyboard_codes.h"
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/geometry/point_f.h"
#include "ui/gfx/geometry/rect.h"
@@ -77,6 +79,8 @@ class MockTestClient : public TestClient {
int32_t result,
base::TimeDelta delay),
(override));
+ MOCK_METHOD(void, DocumentFocusChanged, (bool), (override));
+ MOCK_METHOD(void, SetLinkUnderCursor, (const std::string&), (override));
};
} // namespace
@@ -129,6 +133,17 @@ class PDFiumEngineTest : public PDFiumTestBase {
return loaded_incrementally;
}
+ void FinishWithPluginSizeUpdated(MockTestClient& client,
+ PDFiumEngine& engine) {
+ ResultCallback callback;
+ EXPECT_CALL(client, ScheduleTaskOnMainThread)
+ .WillOnce(MoveArg<1>(&callback));
+ engine.PluginSizeUpdated({});
+
+ ASSERT_TRUE(callback);
+ std::move(callback).Run(0);
+ }
+
// Counts the number of available pages. Returns `int` instead of `size_t` for
// consistency with `PDFiumEngine::GetNumberOfPages()`.
int CountAvailablePages(const PDFiumEngine& engine) {
@@ -249,6 +264,23 @@ TEST_F(PDFiumEngineTest, ProposeDocumentLayoutWithOverlap) {
engine->RotateCounterclockwise();
}
+TEST_F(PDFiumEngineTest, ApplyDocumentLayoutBeforePluginSizeUpdated) {
+ NiceMock<MockTestClient> client;
+ InitializeEngineResult initialize_result = InitializeEngineWithoutLoading(
+ &client, FILE_PATH_LITERAL("rectangles_multi_pages.pdf"));
+ ASSERT_TRUE(initialize_result.engine);
+ initialize_result.FinishLoading();
+ PDFiumEngine& engine = *initialize_result.engine;
+
+ DocumentLayout::Options options;
+ options.RotatePagesClockwise();
+ EXPECT_CALL(client, ScrollToPage(-1)).Times(0);
+ EXPECT_EQ(gfx::Size(343, 1664), engine.ApplyDocumentLayout(options));
+
+ EXPECT_CALL(client, ScrollToPage(-1)).Times(1);
+ ASSERT_NO_FATAL_FAILURE(FinishWithPluginSizeUpdated(client, engine));
+}
+
TEST_F(PDFiumEngineTest, ApplyDocumentLayoutAvoidsInfiniteLoop) {
NiceMock<MockTestClient> client;
std::unique_ptr<PDFiumEngine> engine = InitializeEngine(
@@ -477,14 +509,8 @@ TEST_F(PDFiumEngineTest, PluginSizeUpdatedAfterLoad) {
ASSERT_TRUE(initialize_result.engine);
PDFiumEngine& engine = *initialize_result.engine;
- ResultCallback callback;
- EXPECT_CALL(client, ScheduleTaskOnMainThread).WillOnce(MoveArg<1>(&callback));
-
initialize_result.FinishLoading();
- engine.PluginSizeUpdated({});
-
- ASSERT_TRUE(callback);
- std::move(callback).Run(0);
+ ASSERT_NO_FATAL_FAILURE(FinishWithPluginSizeUpdated(client, engine));
EXPECT_EQ(engine.GetNumberOfPages(), CountAvailablePages(engine));
}
@@ -597,6 +623,35 @@ TEST_F(PDFiumEngineTest, RequestThumbnailLinearized) {
initialize_result.FinishLoading();
}
+TEST_F(PDFiumEngineTest, HandleInputEventKeyDown) {
+ NiceMock<MockTestClient> client;
+ std::unique_ptr<PDFiumEngine> engine =
+ InitializeEngine(&client, FILE_PATH_LITERAL("hello_world2.pdf"));
+ ASSERT_TRUE(engine);
+ EXPECT_CALL(client, DocumentFocusChanged(true));
+
+ blink::WebKeyboardEvent key_down_event(
+ blink::WebInputEvent::Type::kKeyDown, blink::WebInputEvent::kNoModifiers,
+ blink::WebInputEvent::GetStaticTimeStampForTests());
+ key_down_event.windows_key_code = ui::VKEY_TAB;
+ EXPECT_TRUE(engine->HandleInputEvent(key_down_event));
+}
+
+TEST_F(PDFiumEngineTest, HandleInputEventRawKeyDown) {
+ NiceMock<MockTestClient> client;
+ std::unique_ptr<PDFiumEngine> engine =
+ InitializeEngine(&client, FILE_PATH_LITERAL("hello_world2.pdf"));
+ ASSERT_TRUE(engine);
+ EXPECT_CALL(client, DocumentFocusChanged(true));
+
+ blink::WebKeyboardEvent raw_key_down_event(
+ blink::WebInputEvent::Type::kRawKeyDown,
+ blink::WebInputEvent::kNoModifiers,
+ blink::WebInputEvent::GetStaticTimeStampForTests());
+ raw_key_down_event.windows_key_code = ui::VKEY_TAB;
+ EXPECT_TRUE(engine->HandleInputEvent(raw_key_down_event));
+}
+
using PDFiumEngineDeathTest = PDFiumEngineTest;
TEST_F(PDFiumEngineDeathTest, RequestThumbnailRedundant) {
@@ -622,18 +677,6 @@ TEST_F(PDFiumEngineDeathTest, RequestThumbnailRedundant) {
/*page_index=*/1, /*device_pixel_ratio=*/1, mock_callback.Get()));
}
-class TabbingTestClient : public TestClient {
- public:
- TabbingTestClient() = default;
- ~TabbingTestClient() override = default;
- TabbingTestClient(const TabbingTestClient&) = delete;
- TabbingTestClient& operator=(const TabbingTestClient&) = delete;
-
- // Mock PDFEngine::Client methods.
- MOCK_METHOD(void, DocumentFocusChanged, (bool), (override));
- MOCK_METHOD(void, SetLinkUnderCursor, (const std::string&), (override));
-};
-
class PDFiumEngineTabbingTest : public PDFiumTestBase {
public:
PDFiumEngineTabbingTest() = default;
@@ -690,7 +733,7 @@ TEST_F(PDFiumEngineTabbingTest, LinkUnderCursorTest) {
scoped_feature_list.InitAndEnableFeature(
chrome_pdf::features::kTabAcrossPDFAnnotations);
- TabbingTestClient client;
+ NiceMock<MockTestClient> client;
std::unique_ptr<PDFiumEngine> engine =
InitializeEngine(&client, FILE_PATH_LITERAL("annots.pdf"));
ASSERT_TRUE(engine);
@@ -786,7 +829,7 @@ TEST_F(PDFiumEngineTabbingTest, TabbingForwardTest) {
* ++ Page 2
* ++++ Annotation
*/
- NiceMock<TabbingTestClient> client;
+ NiceMock<MockTestClient> client;
std::unique_ptr<PDFiumEngine> engine = InitializeEngine(
&client, FILE_PATH_LITERAL("annotation_form_fields.pdf"));
ASSERT_TRUE(engine);
@@ -838,7 +881,7 @@ TEST_F(PDFiumEngineTabbingTest, TabbingBackwardTest) {
* ++ Page 2
* ++++ Annotation
*/
- NiceMock<TabbingTestClient> client;
+ NiceMock<MockTestClient> client;
std::unique_ptr<PDFiumEngine> engine = InitializeEngine(
&client, FILE_PATH_LITERAL("annotation_form_fields.pdf"));
ASSERT_TRUE(engine);
@@ -945,7 +988,7 @@ TEST_F(PDFiumEngineTabbingTest, NoFocusableItemTabbingTest) {
* ++ Page 1
* ++ Page 2
*/
- NiceMock<TabbingTestClient> client;
+ NiceMock<MockTestClient> client;
std::unique_ptr<PDFiumEngine> engine =
InitializeEngine(&client, FILE_PATH_LITERAL("hello_world2.pdf"));
ASSERT_TRUE(engine);
@@ -994,7 +1037,7 @@ TEST_F(PDFiumEngineTabbingTest, RestoringDocumentFocusTest) {
* ++ Page 2
* ++++ Annotation
*/
- NiceMock<TabbingTestClient> client;
+ NiceMock<MockTestClient> client;
std::unique_ptr<PDFiumEngine> engine = InitializeEngine(
&client, FILE_PATH_LITERAL("annotation_form_fields.pdf"));
ASSERT_TRUE(engine);
@@ -1039,7 +1082,7 @@ TEST_F(PDFiumEngineTabbingTest, RestoringAnnotFocusTest) {
* ++ Page 2
* ++++ Annotation
*/
- NiceMock<TabbingTestClient> client;
+ NiceMock<MockTestClient> client;
std::unique_ptr<PDFiumEngine> engine = InitializeEngine(
&client, FILE_PATH_LITERAL("annotation_form_fields.pdf"));
ASSERT_TRUE(engine);
diff --git a/chromium/pdf/pdfium/pdfium_form_filler.cc b/chromium/pdf/pdfium/pdfium_form_filler.cc
index e16f3c65ff3..829962e9bda 100644
--- a/chromium/pdf/pdfium/pdfium_form_filler.cc
+++ b/chromium/pdf/pdfium/pdfium_form_filler.cc
@@ -5,6 +5,7 @@
#include "pdf/pdfium/pdfium_form_filler.h"
#include <algorithm>
+#include <memory>
#include <string>
#include <utility>
@@ -18,8 +19,10 @@
#include "pdf/pdf_features.h"
#include "pdf/pdfium/pdfium_engine.h"
#include "third_party/blink/public/common/input/web_input_event.h"
+#include "third_party/blink/public/web/blink.h"
#include "third_party/pdfium/public/fpdf_annot.h"
#include "ui/gfx/geometry/rect.h"
+#include "v8/include/v8-isolate.h"
namespace chrome_pdf {
@@ -44,7 +47,7 @@ PDFiumFormFiller::ScriptOption PDFiumFormFiller::DefaultScriptOption() {
PDFiumFormFiller::PDFiumFormFiller(PDFiumEngine* engine,
ScriptOption script_option)
- : engine_(engine), script_option_(script_option) {
+ : engine_in_isolate_scope_factory_(engine), script_option_(script_option) {
// Initialize FPDF_FORMFILLINFO member variables. Deriving from this struct
// allows the static callbacks to be able to cast the FPDF_FORMFILLINFO in
// callbacks to ourself instead of maintaining a map of them to
@@ -132,7 +135,8 @@ void PDFiumFormFiller::Form_Invalidate(FPDF_FORMFILLINFO* param,
double top,
double right,
double bottom) {
- PDFiumEngine* engine = GetEngine(param);
+ EngineInIsolateScope engine_scope = GetEngineInIsolateScope(param);
+ PDFiumEngine* engine = engine_scope.engine();
int page_index = engine->GetVisiblePageIndex(page);
if (page_index == -1) {
// This can sometime happen when the page is closed because it went off
@@ -153,7 +157,8 @@ void PDFiumFormFiller::Form_OutputSelectedRect(FPDF_FORMFILLINFO* param,
double top,
double right,
double bottom) {
- PDFiumEngine* engine = GetEngine(param);
+ EngineInIsolateScope engine_scope = GetEngineInIsolateScope(param);
+ PDFiumEngine* engine = engine_scope.engine();
int page_index = engine->GetVisiblePageIndex(page);
if (page_index == -1)
return;
@@ -179,8 +184,7 @@ int PDFiumFormFiller::Form_SetTimer(FPDF_FORMFILLINFO* param,
int elapse,
TimerCallback timer_func) {
auto* form_filler = static_cast<PDFiumFormFiller*>(param);
- return form_filler->SetTimer(base::TimeDelta::FromMilliseconds(elapse),
- timer_func);
+ return form_filler->SetTimer(base::Milliseconds(elapse), timer_func);
}
// static
@@ -209,7 +213,8 @@ FPDF_SYSTEMTIME PDFiumFormFiller::Form_GetLocalTime(FPDF_FORMFILLINFO* param) {
// static
void PDFiumFormFiller::Form_OnChange(FPDF_FORMFILLINFO* param) {
- PDFiumEngine* engine = GetEngine(param);
+ EngineInIsolateScope engine_scope = GetEngineInIsolateScope(param);
+ PDFiumEngine* engine = engine_scope.engine();
engine->EnteredEditMode();
}
@@ -217,7 +222,8 @@ void PDFiumFormFiller::Form_OnChange(FPDF_FORMFILLINFO* param) {
FPDF_PAGE PDFiumFormFiller::Form_GetPage(FPDF_FORMFILLINFO* param,
FPDF_DOCUMENT document,
int page_index) {
- PDFiumEngine* engine = GetEngine(param);
+ EngineInIsolateScope engine_scope = GetEngineInIsolateScope(param);
+ PDFiumEngine* engine = engine_scope.engine();
if (!engine->PageIndexInBounds(page_index))
return nullptr;
return engine->pages_[page_index]->GetPage();
@@ -226,7 +232,8 @@ FPDF_PAGE PDFiumFormFiller::Form_GetPage(FPDF_FORMFILLINFO* param,
// static
FPDF_PAGE PDFiumFormFiller::Form_GetCurrentPage(FPDF_FORMFILLINFO* param,
FPDF_DOCUMENT document) {
- PDFiumEngine* engine = GetEngine(param);
+ EngineInIsolateScope engine_scope = GetEngineInIsolateScope(param);
+ PDFiumEngine* engine = engine_scope.engine();
int index = engine->last_focused_page_;
if (index == -1) {
index = engine->GetMostVisiblePage();
@@ -247,7 +254,8 @@ int PDFiumFormFiller::Form_GetRotation(FPDF_FORMFILLINFO* param,
// static
void PDFiumFormFiller::Form_ExecuteNamedAction(FPDF_FORMFILLINFO* param,
FPDF_BYTESTRING named_action) {
- PDFiumEngine* engine = GetEngine(param);
+ EngineInIsolateScope engine_scope = GetEngineInIsolateScope(param);
+ PDFiumEngine* engine = engine_scope.engine();
std::string action(named_action);
if (action == "Print") {
engine->client_->Print();
@@ -294,7 +302,8 @@ void PDFiumFormFiller::Form_SetTextFieldFocus(FPDF_FORMFILLINFO* param,
void PDFiumFormFiller::Form_OnFocusChange(FPDF_FORMFILLINFO* param,
FPDF_ANNOTATION annot,
int page_index) {
- PDFiumEngine* engine = GetEngine(param);
+ EngineInIsolateScope engine_scope = GetEngineInIsolateScope(param);
+ PDFiumEngine* engine = engine_scope.engine();
if (!engine->PageIndexInBounds(page_index))
return;
@@ -309,7 +318,8 @@ void PDFiumFormFiller::Form_OnFocusChange(FPDF_FORMFILLINFO* param,
// static
void PDFiumFormFiller::Form_DoURIAction(FPDF_FORMFILLINFO* param,
FPDF_BYTESTRING uri) {
- PDFiumEngine* engine = GetEngine(param);
+ EngineInIsolateScope engine_scope = GetEngineInIsolateScope(param);
+ PDFiumEngine* engine = engine_scope.engine();
engine->client_->NavigateTo(std::string(uri),
WindowOpenDisposition::CURRENT_TAB);
}
@@ -320,7 +330,8 @@ void PDFiumFormFiller::Form_DoGoToAction(FPDF_FORMFILLINFO* param,
int zoom_mode,
float* position_array,
int size_of_array) {
- PDFiumEngine* engine = GetEngine(param);
+ EngineInIsolateScope engine_scope = GetEngineInIsolateScope(param);
+ PDFiumEngine* engine = engine_scope.engine();
engine->ScrollToPage(page_index);
}
@@ -329,7 +340,8 @@ void PDFiumFormFiller::Form_DoURIActionWithKeyboardModifier(
FPDF_FORMFILLINFO* param,
FPDF_BYTESTRING uri,
int modifiers) {
- PDFiumEngine* engine = GetEngine(param);
+ EngineInIsolateScope engine_scope = GetEngineInIsolateScope(param);
+ PDFiumEngine* engine = engine_scope.engine();
bool middle_button =
!!(modifiers & blink::WebInputEvent::Modifiers::kMiddleButtonDown);
bool alt_key = !!(modifiers & blink::WebInputEvent::Modifiers::kAltKey);
@@ -360,7 +372,8 @@ void PDFiumFormFiller::Form_EmailTo(FPDF_FORMFILLINFO* param,
std::string bcc_str = WideStringToString(bcc);
std::string message_str = WideStringToString(message);
- PDFiumEngine* engine = GetEngine(param);
+ EngineInIsolateScope engine_scope = GetEngineInIsolateScope(param);
+ PDFiumEngine* engine = engine_scope.engine();
engine->client_->Email(to_str, cc_str, bcc_str, subject_str, message_str);
}
@@ -377,14 +390,16 @@ void PDFiumFormFiller::Form_DisplayCaret(FPDF_FORMFILLINFO* param,
void PDFiumFormFiller::Form_SetCurrentPage(FPDF_FORMFILLINFO* param,
FPDF_DOCUMENT document,
int page) {
- PDFiumEngine* engine = GetEngine(param);
+ EngineInIsolateScope engine_scope = GetEngineInIsolateScope(param);
+ PDFiumEngine* engine = engine_scope.engine();
engine->ScrollToPage(page);
}
// static
int PDFiumFormFiller::Form_GetCurrentPageIndex(FPDF_FORMFILLINFO* param,
FPDF_DOCUMENT document) {
- PDFiumEngine* engine = GetEngine(param);
+ EngineInIsolateScope engine_scope = GetEngineInIsolateScope(param);
+ PDFiumEngine* engine = engine_scope.engine();
return engine->GetMostVisiblePage();
}
@@ -395,7 +410,8 @@ void PDFiumFormFiller::Form_GetPageViewRect(FPDF_FORMFILLINFO* param,
double* top,
double* right,
double* bottom) {
- PDFiumEngine* engine = GetEngine(param);
+ EngineInIsolateScope engine_scope = GetEngineInIsolateScope(param);
+ PDFiumEngine* engine = engine_scope.engine();
int page_index = engine->GetVisiblePageIndex(page);
if (!engine->PageIndexInBounds(page_index)) {
*left = 0;
@@ -474,7 +490,8 @@ void PDFiumFormFiller::Form_PageEvent(FPDF_FORMFILLINFO* param,
DCHECK(event_type == FXFA_PAGEVIEWEVENT_POSTADDED ||
event_type == FXFA_PAGEVIEWEVENT_POSTREMOVED);
- PDFiumEngine* engine = GetEngine(param);
+ EngineInIsolateScope engine_scope = GetEngineInIsolateScope(param);
+ PDFiumEngine* engine = engine_scope.engine();
engine->UpdatePageCount();
}
@@ -579,7 +596,8 @@ int PDFiumFormFiller::Form_Alert(IPDF_JSPLATFORM* param,
ALERT_RESULT_YES
};
- PDFiumEngine* engine = GetEngine(param);
+ EngineInIsolateScope engine_scope = GetEngineInIsolateScope(param);
+ PDFiumEngine* engine = engine_scope.engine();
std::string message_str = WideStringToString(message);
if (type == ALERT_TYPE_OK) {
engine->client_->Alert(message_str);
@@ -594,7 +612,8 @@ int PDFiumFormFiller::Form_Alert(IPDF_JSPLATFORM* param,
// static
void PDFiumFormFiller::Form_Beep(IPDF_JSPLATFORM* param, int type) {
- PDFiumEngine* engine = GetEngine(param);
+ EngineInIsolateScope engine_scope = GetEngineInIsolateScope(param);
+ PDFiumEngine* engine = engine_scope.engine();
engine->client_->Beep();
}
@@ -610,7 +629,8 @@ int PDFiumFormFiller::Form_Response(IPDF_JSPLATFORM* param,
std::string question_str = WideStringToString(question);
std::string default_str = WideStringToString(default_response);
- PDFiumEngine* engine = GetEngine(param);
+ EngineInIsolateScope engine_scope = GetEngineInIsolateScope(param);
+ PDFiumEngine* engine = engine_scope.engine();
std::string rv = engine->client_->Prompt(question_str, default_str);
std::u16string rv_16 = base::UTF8ToUTF16(rv);
int rv_bytes = rv_16.size() * sizeof(char16_t);
@@ -625,7 +645,8 @@ int PDFiumFormFiller::Form_Response(IPDF_JSPLATFORM* param,
int PDFiumFormFiller::Form_GetFilePath(IPDF_JSPLATFORM* param,
void* file_path,
int length) {
- PDFiumEngine* engine = GetEngine(param);
+ EngineInIsolateScope engine_scope = GetEngineInIsolateScope(param);
+ PDFiumEngine* engine = engine_scope.engine();
std::string rv = engine->client_->GetURL();
if (file_path && rv.size() <= static_cast<size_t>(length))
memcpy(file_path, rv.c_str(), rv.size());
@@ -650,7 +671,8 @@ void PDFiumFormFiller::Form_Mail(IPDF_JSPLATFORM* param,
std::string subject_str = WideStringToString(subject);
std::string message_str = WideStringToString(message);
- PDFiumEngine* engine = GetEngine(param);
+ EngineInIsolateScope engine_scope = GetEngineInIsolateScope(param);
+ PDFiumEngine* engine = engine_scope.engine();
engine->client_->Email(to_str, cc_str, bcc_str, subject_str, message_str);
}
@@ -666,7 +688,8 @@ void PDFiumFormFiller::Form_Print(IPDF_JSPLATFORM* param,
FPDF_BOOL annotations) {
// No way to pass the extra information to the print dialog using JavaScript.
// Just opening it is fine for now.
- PDFiumEngine* engine = GetEngine(param);
+ EngineInIsolateScope engine_scope = GetEngineInIsolateScope(param);
+ PDFiumEngine* engine = engine_scope.engine();
engine->client_->Print();
}
@@ -676,28 +699,67 @@ void PDFiumFormFiller::Form_SubmitForm(IPDF_JSPLATFORM* param,
int length,
FPDF_WIDESTRING url) {
std::string url_str = WideStringToString(url);
- PDFiumEngine* engine = GetEngine(param);
+ EngineInIsolateScope engine_scope = GetEngineInIsolateScope(param);
+ PDFiumEngine* engine = engine_scope.engine();
engine->client_->SubmitForm(url_str, form_data, length);
}
// static
void PDFiumFormFiller::Form_GotoPage(IPDF_JSPLATFORM* param, int page_number) {
- PDFiumEngine* engine = GetEngine(param);
+ EngineInIsolateScope engine_scope = GetEngineInIsolateScope(param);
+ PDFiumEngine* engine = engine_scope.engine();
engine->ScrollToPage(page_number);
}
#endif // defined(PDF_ENABLE_V8)
+PDFiumFormFiller::EngineInIsolateScope::EngineInIsolateScope(
+ PDFiumEngine* engine,
+ v8::Isolate* isolate)
+ : isolate_scope_(isolate ? std::make_unique<v8::Isolate::Scope>(isolate)
+ : nullptr),
+ engine_(engine) {
+ DCHECK(engine_);
+}
+
+PDFiumFormFiller::EngineInIsolateScope::EngineInIsolateScope(
+ EngineInIsolateScope&&) = default;
+
+PDFiumFormFiller::EngineInIsolateScope&
+PDFiumFormFiller::EngineInIsolateScope::operator=(EngineInIsolateScope&&) =
+ default;
+
+PDFiumFormFiller::EngineInIsolateScope::~EngineInIsolateScope() = default;
+
+PDFiumFormFiller::EngineInIsolateScopeFactory::EngineInIsolateScopeFactory(
+ PDFiumEngine* engine)
+ : engine_(engine), callback_isolate_(v8::Isolate::TryGetCurrent()) {
+ if (callback_isolate_)
+ CHECK_EQ(blink::MainThreadIsolate(), callback_isolate_);
+}
+
+PDFiumFormFiller::EngineInIsolateScopeFactory::~EngineInIsolateScopeFactory() =
+ default;
+
+PDFiumFormFiller::EngineInIsolateScope
+PDFiumFormFiller::EngineInIsolateScopeFactory::GetEngineInIsolateScope() const {
+ return EngineInIsolateScope(engine_, callback_isolate_);
+}
+
// static
-PDFiumEngine* PDFiumFormFiller::GetEngine(FPDF_FORMFILLINFO* info) {
+PDFiumFormFiller::EngineInIsolateScope
+PDFiumFormFiller::GetEngineInIsolateScope(FPDF_FORMFILLINFO* info) {
auto* form_filler = static_cast<PDFiumFormFiller*>(info);
- return form_filler->engine_;
+ return form_filler->engine_in_isolate_scope_factory_
+ .GetEngineInIsolateScope();
}
// static
-PDFiumEngine* PDFiumFormFiller::GetEngine(IPDF_JSPLATFORM* platform) {
+PDFiumFormFiller::EngineInIsolateScope
+PDFiumFormFiller::GetEngineInIsolateScope(IPDF_JSPLATFORM* platform) {
auto* form_filler = static_cast<PDFiumFormFiller*>(platform);
- return form_filler->engine_;
+ return form_filler->engine_in_isolate_scope_factory_
+ .GetEngineInIsolateScope();
}
int PDFiumFormFiller::SetTimer(const base::TimeDelta& delay,
diff --git a/chromium/pdf/pdfium/pdfium_form_filler.h b/chromium/pdf/pdfium/pdfium_form_filler.h
index 53b206e7d66..aabd121a747 100644
--- a/chromium/pdf/pdfium/pdfium_form_filler.h
+++ b/chromium/pdf/pdfium/pdfium_form_filler.h
@@ -12,6 +12,7 @@
#include "base/timer/timer.h"
#include "third_party/pdfium/public/fpdf_formfill.h"
#include "third_party/pdfium/public/fpdfview.h"
+#include "v8/include/v8-isolate.h"
namespace chrome_pdf {
@@ -189,13 +190,53 @@ class PDFiumFormFiller : public FPDF_FORMFILLINFO, public IPDF_JSPLATFORM {
static void Form_GotoPage(IPDF_JSPLATFORM* param, int page_number);
#endif // defined(PDF_ENABLE_V8)
- static PDFiumEngine* GetEngine(FPDF_FORMFILLINFO* info);
- static PDFiumEngine* GetEngine(IPDF_JSPLATFORM* platform);
+ // A utility class that helps in enforcing accesses of `PDFiumEngine` within a
+ // given `v8::Isolate`. The entries of the isolates are scoped to the
+ // lifetimes of its instances. This class is tolerant of null isolates.
+ class EngineInIsolateScope {
+ public:
+ EngineInIsolateScope(PDFiumEngine* engine, v8::Isolate* isolate);
+ EngineInIsolateScope(EngineInIsolateScope&&);
+ EngineInIsolateScope& operator=(EngineInIsolateScope&&);
+ ~EngineInIsolateScope();
+
+ PDFiumEngine* engine() { return engine_; }
+
+ private:
+ std::unique_ptr<v8::Isolate::Scope> isolate_scope_;
+ PDFiumEngine* engine_;
+ };
+
+ class EngineInIsolateScopeFactory {
+ public:
+ explicit EngineInIsolateScopeFactory(PDFiumEngine* engine);
+ EngineInIsolateScopeFactory(const EngineInIsolateScope&) = delete;
+ EngineInIsolateScopeFactory& operator=(
+ const EngineInIsolateScopeFactory&&) = delete;
+ ~EngineInIsolateScopeFactory();
+
+ // Retrieves `engine_` while attempting to enter `callback_isolate_`.
+ EngineInIsolateScope GetEngineInIsolateScope() const;
+
+ private:
+ PDFiumEngine* const engine_;
+
+ // The V8 isolate to enter inside callbacks from PDFium. Can be `nullptr`
+ // because indirect callers of `PDFiumFormFiller` might not be embedding V8
+ // separately. This can happen in utility processes (through callers of
+ // //pdf/pdf.h) and in Pepper plugin processes.
+ v8::Isolate* const callback_isolate_;
+ };
+
+ // Gets an `EngineInIsolateScope` using `engine_in_isolate_scope_factory_`.
+ static EngineInIsolateScope GetEngineInIsolateScope(FPDF_FORMFILLINFO* info);
+ static EngineInIsolateScope GetEngineInIsolateScope(
+ IPDF_JSPLATFORM* platform);
int SetTimer(const base::TimeDelta& delay, TimerCallback timer_func);
void KillTimer(int timer_id);
- PDFiumEngine* const engine_;
+ const EngineInIsolateScopeFactory engine_in_isolate_scope_factory_;
const ScriptOption script_option_;
std::map<int, std::unique_ptr<base::RepeatingTimer>> timers_;
};
diff --git a/chromium/pdf/pdfium/pdfium_form_filler_unittest.cc b/chromium/pdf/pdfium/pdfium_form_filler_unittest.cc
index c86242b57b9..24b6e9dc48e 100644
--- a/chromium/pdf/pdfium/pdfium_form_filler_unittest.cc
+++ b/chromium/pdf/pdfium/pdfium_form_filler_unittest.cc
@@ -2,22 +2,29 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "pdf/pdfium/pdfium_form_filler.h"
+
+#include "base/threading/thread_task_runner_handle.h"
#include "build/build_config.h"
+#include "gin/public/isolate_holder.h"
#include "pdf/pdfium/pdfium_engine.h"
#include "pdf/pdfium/pdfium_test_base.h"
#include "pdf/test/test_client.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "third_party/blink/public/common/input/web_input_event.h"
+#include "third_party/blink/public/web/blink.h"
#include "third_party/pdfium/public/fpdf_annot.h"
+#include "third_party/pdfium/public/fpdf_formfill.h"
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/geometry/size.h"
-
-using testing::InSequence;
+#include "v8/include/v8-isolate.h"
namespace chrome_pdf {
namespace {
+using ::testing::InSequence;
+
class FormFillerTestClient : public TestClient {
public:
FormFillerTestClient() = default;
@@ -26,6 +33,7 @@ class FormFillerTestClient : public TestClient {
FormFillerTestClient& operator=(const FormFillerTestClient&) = delete;
// Mock PDFEngine::Client methods.
+ MOCK_METHOD(void, Beep, (), (override));
MOCK_METHOD(void, ScrollToX, (int), (override));
MOCK_METHOD(void, ScrollToY, (int), (override));
MOCK_METHOD(void,
@@ -58,6 +66,12 @@ class FormFillerTest : public PDFiumTestBase {
engine->form_filler_.Form_DoURIActionWithKeyboardModifier(
&engine->form_filler_, uri, modifiers);
}
+
+ void TriggerBeep(PDFiumEngine* engine) {
+ ASSERT_TRUE(engine);
+ engine->form_filler_.Form_Beep(&engine->form_filler_,
+ JSPLATFORM_BEEP_DEFAULT);
+ }
};
TEST_F(FormFillerTest, DoURIActionWithKeyboardModifier) {
@@ -161,4 +175,40 @@ TEST_F(FormFillerTest, FormOnFocusChange) {
}
}
+class FormFillerIsolateTest : public FormFillerTest {
+ public:
+ FormFillerIsolateTest() {
+ // Needed for setting up V8.
+ InitializeSDK(/*enable_v8=*/true, FontMappingMode::kNoMapping);
+ }
+
+ ~FormFillerIsolateTest() override { ShutdownSDK(); }
+};
+
+TEST_F(FormFillerIsolateTest, IsolateScoping) {
+ // Enter the embedder's isolate so it can be captured when the
+ // `PDFiumFormFiller` is created.
+ v8::Isolate* embedder_isolate = blink::MainThreadIsolate();
+ v8::Isolate::Scope embedder_isolate_scope(embedder_isolate);
+
+ FormFillerTestClient client;
+ PDFiumEngine engine(&client, PDFiumFormFiller::ScriptOption::kJavaScript);
+
+ gin::IsolateHolder pdfium_test_isolate_holder(
+ base::ThreadTaskRunnerHandle::Get(),
+ gin::IsolateHolder::IsolateType::kTest);
+ v8::Isolate* pdfium_test_isolate = pdfium_test_isolate_holder.isolate();
+
+ // Enter PDFium's isolate and then trigger a beep callback. The embedder's
+ // isolate should be entered during the callback's execution.
+ v8::Isolate::Scope pdfium_test_isolate_scope(pdfium_test_isolate);
+ EXPECT_CALL(client, Beep).WillOnce([&embedder_isolate]() {
+ EXPECT_EQ(v8::Isolate::TryGetCurrent(), embedder_isolate);
+ });
+ TriggerBeep(&engine);
+
+ // PDFium's isolate should be entered again after the callback completes.
+ EXPECT_EQ(v8::Isolate::TryGetCurrent(), pdfium_test_isolate);
+}
+
} // namespace chrome_pdf
diff --git a/chromium/pdf/pdfium/pdfium_print_unittest.cc b/chromium/pdf/pdfium/pdfium_print_unittest.cc
index 128f109e812..9dd62a9bdb7 100644
--- a/chromium/pdf/pdfium/pdfium_print_unittest.cc
+++ b/chromium/pdf/pdfium/pdfium_print_unittest.cc
@@ -23,7 +23,7 @@
#include "third_party/skia/include/core/SkImageInfo.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/size_f.h"
-#include "ui/gfx/skia_util.h"
+#include "ui/gfx/geometry/skia_conversions.h"
namespace chrome_pdf {
diff --git a/chromium/pdf/ppapi_migration/graphics.cc b/chromium/pdf/ppapi_migration/graphics.cc
index 0083a0ef521..4b03fb30723 100644
--- a/chromium/pdf/ppapi_migration/graphics.cc
+++ b/chromium/pdf/ppapi_migration/graphics.cc
@@ -26,8 +26,8 @@
#include "ui/gfx/blit.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/size.h"
+#include "ui/gfx/geometry/skia_conversions.h"
#include "ui/gfx/geometry/vector2d.h"
-#include "ui/gfx/skia_util.h"
namespace chrome_pdf {
diff --git a/chromium/pdf/ppapi_migration/graphics_unittest.cc b/chromium/pdf/ppapi_migration/graphics_unittest.cc
index 2269534504b..64eb2157e37 100644
--- a/chromium/pdf/ppapi_migration/graphics_unittest.cc
+++ b/chromium/pdf/ppapi_migration/graphics_unittest.cc
@@ -22,7 +22,7 @@
#include "third_party/skia/include/core/SkSurface.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/size.h"
-#include "ui/gfx/skia_util.h"
+#include "ui/gfx/geometry/skia_conversions.h"
namespace chrome_pdf {
diff --git a/chromium/pdf/ppapi_migration/input_event_conversions.cc b/chromium/pdf/ppapi_migration/input_event_conversions.cc
index 8ff8228c27e..16cc97a3fab 100644
--- a/chromium/pdf/ppapi_migration/input_event_conversions.cc
+++ b/chromium/pdf/ppapi_migration/input_event_conversions.cc
@@ -43,15 +43,9 @@ blink::WebInputEvent::Type GetWebInputEventType(PP_InputEvent_Type event_type) {
case PP_INPUTEVENT_TYPE_WHEEL:
return blink::WebInputEvent::Type::kMouseWheel;
case PP_INPUTEVENT_TYPE_RAWKEYDOWN:
- case PP_INPUTEVENT_TYPE_KEYDOWN:
- // Blink no longer passes `kKeyDown` events into plugins, and instead
- // passes `kRawKeyDown` events. However, `kRawKeyDown` gets mapped to
- // `PP_INPUTEVENT_TYPE_KEYDOWN` for backwards compatibility. Map both
- // Pepper enums to `kRawKeyDown` to allow for a common implementation
- // between the Pepper and Pepper-free plugins.
- // See the comments inside the definition of `ConvertEventTypes()` in
- // content/renderer/pepper/event_conversion.cc.
return blink::WebInputEvent::Type::kRawKeyDown;
+ case PP_INPUTEVENT_TYPE_KEYDOWN:
+ return blink::WebInputEvent::Type::kKeyDown;
case PP_INPUTEVENT_TYPE_KEYUP:
return blink::WebInputEvent::Type::kKeyUp;
case PP_INPUTEVENT_TYPE_CHAR:
@@ -95,7 +89,7 @@ std::unique_ptr<blink::WebMouseEvent> GetWebMouseEvent(
auto mouse_event = std::make_unique<blink::WebMouseEvent>(
type, event.GetModifiers(),
- base::TimeTicks() + base::TimeDelta::FromSecondsD(event.GetTimeStamp()));
+ base::TimeTicks() + base::Seconds(event.GetTimeStamp()));
mouse_event->button = GetWebPointerPropertiesButton(event.GetButton());
mouse_event->click_count = event.GetClickCount();
@@ -113,7 +107,7 @@ std::unique_ptr<blink::WebKeyboardEvent> GetWebKeyboardEvent(
auto keyboard_event = std::make_unique<blink::WebKeyboardEvent>(
type, event.GetModifiers(),
- base::TimeTicks() + base::TimeDelta::FromSecondsD(event.GetTimeStamp()));
+ base::TimeTicks() + base::Seconds(event.GetTimeStamp()));
keyboard_event->windows_key_code = event.GetKeyCode();
@@ -136,7 +130,7 @@ std::unique_ptr<blink::WebTouchEvent> GetWebTouchEvent(
auto touch_event = std::make_unique<blink::WebTouchEvent>(
type, event.GetModifiers(),
- base::TimeTicks() + base::TimeDelta::FromSecondsD(event.GetTimeStamp()));
+ base::TimeTicks() + base::Seconds(event.GetTimeStamp()));
// The PDF plugin only cares about the first touch and the number of touches,
// but copy over all the touches so that `touch_event->touches_length`
@@ -164,6 +158,7 @@ std::unique_ptr<blink::WebInputEvent> GetWebInputEvent(
case blink::WebInputEvent::Type::kMouseLeave:
return GetWebMouseEvent(pp::MouseInputEvent(event));
case blink::WebInputEvent::Type::kRawKeyDown:
+ case blink::WebInputEvent::Type::kKeyDown:
case blink::WebInputEvent::Type::kKeyUp:
case blink::WebInputEvent::Type::kChar:
return GetWebKeyboardEvent(pp::KeyboardInputEvent(event));
diff --git a/chromium/pdf/ppapi_migration/url_loader.cc b/chromium/pdf/ppapi_migration/url_loader.cc
index 6d2d89ec228..59eadb3b795 100644
--- a/chromium/pdf/ppapi_migration/url_loader.cc
+++ b/chromium/pdf/ppapi_migration/url_loader.cc
@@ -345,7 +345,6 @@ void PepperUrlLoader::Open(const UrlRequest& request, ResultCallback callback) {
pp::URLRequestInfo pp_request(plugin_instance_);
pp_request.SetURL(request.url);
pp_request.SetMethod(request.method);
- pp_request.SetCustomReferrerURL(request.url);
if (request.ignore_redirects)
pp_request.SetFollowRedirects(false);
diff --git a/chromium/pdf/url_loader_wrapper_impl.cc b/chromium/pdf/url_loader_wrapper_impl.cc
index 5eb00bc08de..add261cd6fb 100644
--- a/chromium/pdf/url_loader_wrapper_impl.cc
+++ b/chromium/pdf/url_loader_wrapper_impl.cc
@@ -29,7 +29,7 @@ namespace chrome_pdf {
namespace {
// We should read with delay to prevent block UI thread, and reduce CPU usage.
-constexpr base::TimeDelta kReadDelayMs = base::TimeDelta::FromMilliseconds(2);
+constexpr base::TimeDelta kReadDelayMs = base::Milliseconds(2);
UrlRequest MakeRangeRequest(const std::string& url,
const std::string& referrer_url,