diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2020-11-18 16:35:47 +0100 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2020-11-18 15:45:54 +0000 |
commit | 32f5a1c56531e4210bc4cf8d8c7825d66e081888 (patch) | |
tree | eeeec6822f4d738d8454525233fd0e2e3a659e6d /chromium/pdf | |
parent | 99677208ff3b216fdfec551fbe548da5520cd6fb (diff) | |
download | qtwebengine-chromium-32f5a1c56531e4210bc4cf8d8c7825d66e081888.tar.gz |
BASELINE: Update Chromium to 87.0.4280.67
Change-Id: Ib157360be8c2ffb2c73125751a89f60e049c1d54
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/pdf')
61 files changed, 3682 insertions, 1357 deletions
diff --git a/chromium/pdf/BUILD.gn b/chromium/pdf/BUILD.gn index 4f039031947..44022041fbd 100644 --- a/chromium/pdf/BUILD.gn +++ b/chromium/pdf/BUILD.gn @@ -32,6 +32,7 @@ if (enable_pdf) { deps = [ ":internal", "//base", + "//ui/gfx/geometry", ] } @@ -128,6 +129,8 @@ if (enable_pdf) { "preview_mode_client.h", "range_set.cc", "range_set.h", + "thumbnail.cc", + "thumbnail.h", "url_loader_wrapper.h", "url_loader_wrapper_impl.cc", "url_loader_wrapper_impl.h", @@ -193,6 +196,8 @@ if (enable_pdf) { "ppapi_migration/image.h", "ppapi_migration/input_event_conversions.cc", "ppapi_migration/input_event_conversions.h", + "ppapi_migration/url_loader.cc", + "ppapi_migration/url_loader.h", "ppapi_migration/value_conversions.cc", "ppapi_migration/value_conversions.h", ] @@ -205,6 +210,7 @@ if (enable_pdf) { "//base", "//ppapi/cpp:objects", "//skia", + "//third_party/blink/public:blink", "//ui/base", ] } @@ -246,6 +252,7 @@ if (enable_pdf) { deps = [ ":internal", + ":ppapi_migration", "//base", "//cc/paint", "//ppapi/cpp:objects", # TODO(crbug.com/1114263): PDFEngine::Client only. @@ -264,14 +271,13 @@ if (enable_pdf) { "test/test_client.h", "test/test_document_loader.cc", "test/test_document_loader.h", - "test/test_utils.cc", - "test/test_utils.h", ] configs += [ "//build/config/compiler:noshadowing" ] deps = [ ":internal", + ":ppapi_migration", "//base", "//ppapi/cpp:objects", "//testing/gtest", @@ -301,7 +307,10 @@ if (enable_pdf) { "pdfium/pdfium_test_base.cc", "pdfium/pdfium_test_base.h", "ppapi_migration/geometry_conversions_unittest.cc", + "ppapi_migration/url_loader_unittest.cc", "range_set_unittest.cc", + "test/run_all_unittests.cc", + "thumbnail_unittest.cc", ] configs += [ @@ -320,8 +329,8 @@ if (enable_pdf) { ":pdf_test_utils", ":ppapi_migration", "//base", - "//base/test:run_all_unittests", "//base/test:test_support", + "//cc:test_support", "//gin", "//ppapi/c", "//ppapi/cpp:objects", @@ -329,6 +338,7 @@ if (enable_pdf) { "//skia", "//testing/gmock", "//testing/gtest", + "//third_party/blink/public:blink", "//third_party/pdfium", "//ui/gfx:test_support", "//ui/gfx/geometry", diff --git a/chromium/pdf/accessibility.cc b/chromium/pdf/accessibility.cc index ed259653f69..02283f66abf 100644 --- a/chromium/pdf/accessibility.cc +++ b/chromium/pdf/accessibility.cc @@ -9,6 +9,9 @@ #include "base/numerics/safe_math.h" #include "pdf/pdf_engine.h" +#include "pdf/ppapi_migration/geometry_conversions.h" +#include "ppapi/cpp/rect.h" +#include "ui/gfx/geometry/rect_f.h" namespace chrome_pdf { @@ -73,7 +76,7 @@ void GetAccessibilityLinkInfo( pp::PDF::PrivateAccessibilityLinkInfo link_info; link_info.url = std::move(cur_engine_info.url); link_info.index_in_page = i; - link_info.bounds = std::move(cur_engine_info.bounds); + link_info.bounds = PPFloatRectFromRectF(cur_engine_info.bounds); if (!GetEnclosingTextRunRangeForCharRange( text_runs, cur_engine_info.start_char_index, @@ -103,7 +106,7 @@ void GetAccessibilityImageInfo( for (auto& cur_engine_info : engine_image_info) { pp::PDF::PrivateAccessibilityImageInfo image_info; image_info.alt_text = std::move(cur_engine_info.alt_text); - image_info.bounds = std::move(cur_engine_info.bounds); + image_info.bounds = PPFloatRectFromRectF(cur_engine_info.bounds); // TODO(mohitb): Update text run index to nearest text run to image bounds. image_info.text_run_index = text_run_count; images->push_back(std::move(image_info)); @@ -121,7 +124,7 @@ void GetAccessibilityHighlightInfo( auto& cur_highlight_info = engine_highlight_info[i]; pp::PDF::PrivateAccessibilityHighlightInfo highlight_info; highlight_info.index_in_page = i; - highlight_info.bounds = std::move(cur_highlight_info.bounds); + highlight_info.bounds = PPFloatRectFromRectF(cur_highlight_info.bounds); highlight_info.color = cur_highlight_info.color; highlight_info.note_text = std::move(cur_highlight_info.note_text); @@ -161,7 +164,7 @@ void GetAccessibilityTextFieldInfo( // TODO(crbug.com/1030242): Update text run index to nearest text run to // text field bounds. text_field_info.text_run_index = text_run_count; - text_field_info.bounds = std::move(cur_text_field_info.bounds); + text_field_info.bounds = PPFloatRectFromRectF(cur_text_field_info.bounds); text_fields->push_back(std::move(text_field_info)); } } @@ -196,7 +199,7 @@ bool GetAccessibilityInfo( char_count = 0; page_info->page_index = page_index; - page_info->bounds = engine->GetPageBoundsRect(page_index); + page_info->bounds = PPRectFromRect(engine->GetPageBoundsRect(page_index)); page_info->char_count = char_count; chars->resize(page_info->char_count); @@ -223,10 +226,10 @@ bool GetAccessibilityInfo( // x coordinate of the next. The rest of the bounds of each character // can be computed from the bounds of the text run. // The same idea is used for RTL, TTB and BTT text direction. - pp::FloatRect char_bounds = engine->GetCharBounds(page_index, char_index); + gfx::RectF char_bounds = engine->GetCharBounds(page_index, char_index); for (uint32_t i = char_index; i < text_run_end - 1; i++) { DCHECK_LT(i + 1, static_cast<uint32_t>(char_count)); - pp::FloatRect next_char_bounds = engine->GetCharBounds(page_index, i + 1); + gfx::RectF next_char_bounds = engine->GetCharBounds(page_index, i + 1); double& char_width = (*chars)[i].char_width; switch (text_run_info.direction) { case PP_PRIVATEDIRECTION_NONE: diff --git a/chromium/pdf/document_layout.cc b/chromium/pdf/document_layout.cc index ec6fb10cda0..9f5b12c460c 100644 --- a/chromium/pdf/document_layout.cc +++ b/chromium/pdf/document_layout.cc @@ -8,10 +8,8 @@ #include "base/check_op.h" #include "base/values.h" -#include "ppapi/cpp/rect.h" -#include "ppapi/cpp/var.h" -#include "ppapi/cpp/var_dictionary.h" #include "ui/gfx/geometry/point.h" +#include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/size.h" namespace chrome_pdf { @@ -30,11 +28,12 @@ int GetWidestPageWidth(const std::vector<gfx::Size>& page_sizes) { return widest_page_width; } -pp::Rect InsetRect(pp::Rect rect, - const draw_utils::PageInsetSizes& inset_sizes) { - rect.Inset(inset_sizes.left, inset_sizes.top, inset_sizes.right, - inset_sizes.bottom); - return rect; +gfx::Rect InsetRect(const gfx::Rect& rect, + const draw_utils::PageInsetSizes& inset_sizes) { + gfx::Rect inset_rect(rect); + inset_rect.Inset(inset_sizes.left, inset_sizes.top, inset_sizes.right, + inset_sizes.bottom); + return inset_rect; } } // namespace @@ -58,11 +57,11 @@ base::Value DocumentLayout::Options::ToValue() const { return dictionary; } -void DocumentLayout::Options::FromVar(const pp::Var& var) { - pp::VarDictionary dictionary(var); +void DocumentLayout::Options::FromValue(const base::Value& value) { + DCHECK(value.is_dict()); int32_t default_page_orientation = - dictionary.Get(kDefaultPageOrientation).AsInt(); + value.FindKey(kDefaultPageOrientation)->GetInt(); DCHECK_GE(default_page_orientation, static_cast<int32_t>(PageOrientation::kOriginal)); DCHECK_LE(default_page_orientation, @@ -70,7 +69,7 @@ void DocumentLayout::Options::FromVar(const pp::Var& var) { default_page_orientation_ = static_cast<PageOrientation>(default_page_orientation); - two_up_view_enabled_ = dictionary.Get(kTwoUpViewEnabled).AsBool(); + two_up_view_enabled_ = value.FindKey(kTwoUpViewEnabled)->GetBool(); } void DocumentLayout::Options::RotatePagesClockwise() { @@ -116,11 +115,11 @@ void DocumentLayout::ComputeSingleViewLayout( } const gfx::Size& page_size = page_sizes[i]; - pp::Rect page_rect = + gfx::Rect page_rect = draw_utils::GetRectForSingleView(page_size, document_size); - CopyRectIfModified(page_rect, &page_layouts_[i].outer_rect); + CopyRectIfModified(page_rect, page_layouts_[i].outer_rect); CopyRectIfModified(InsetRect(page_rect, kSingleViewInsets), - &page_layouts_[i].inner_rect); + page_layouts_[i].inner_rect); draw_utils::ExpandDocumentSize(page_size, &document_size); } @@ -147,7 +146,7 @@ void DocumentLayout::ComputeTwoUpViewLayout( i, page_sizes.size(), kSingleViewInsets, kHorizontalSeparator); const gfx::Size& page_size = page_sizes[i]; - pp::Rect page_rect; + gfx::Rect page_rect; if (i % 2 == 0) { page_rect = draw_utils::GetLeftRectForTwoUpView( page_size, {document_size.width(), document_size.height()}); @@ -157,9 +156,9 @@ void DocumentLayout::ComputeTwoUpViewLayout( document_size.Enlarge( 0, std::max(page_size.height(), page_sizes[i - 1].height())); } - CopyRectIfModified(page_rect, &page_layouts_[i].outer_rect); + CopyRectIfModified(page_rect, page_layouts_[i].outer_rect); CopyRectIfModified(InsetRect(page_rect, page_insets), - &page_layouts_[i].inner_rect); + page_layouts_[i].inner_rect); } if (page_sizes.size() % 2 == 1) { @@ -174,10 +173,10 @@ void DocumentLayout::ComputeTwoUpViewLayout( } } -void DocumentLayout::CopyRectIfModified(const pp::Rect& source_rect, - pp::Rect* destination_rect) { - if (*destination_rect != source_rect) { - *destination_rect = source_rect; +void DocumentLayout::CopyRectIfModified(const gfx::Rect& source_rect, + gfx::Rect& destination_rect) { + if (destination_rect != source_rect) { + destination_rect = source_rect; dirty_ = true; } } diff --git a/chromium/pdf/document_layout.h b/chromium/pdf/document_layout.h index 95d63877b74..fb028424e55 100644 --- a/chromium/pdf/document_layout.h +++ b/chromium/pdf/document_layout.h @@ -11,17 +11,13 @@ #include "base/check_op.h" #include "pdf/draw_utils/coordinates.h" #include "pdf/page_orientation.h" -#include "ppapi/cpp/rect.h" +#include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/size.h" namespace base { class Value; } -namespace pp { -class Var; -} // namespace pp - namespace chrome_pdf { // Layout of pages within a PDF document. Pages are placed as rectangles @@ -55,8 +51,8 @@ class DocumentLayout final { // Serializes layout options to a base::Value. base::Value ToValue() const; - // Deserializes layout options from a pp::Var. - void FromVar(const pp::Var& var); + // Deserializes layout options from a base::Value. + void FromValue(const base::Value& value); PageOrientation default_page_orientation() const { return default_page_orientation_; @@ -113,14 +109,14 @@ class DocumentLayout final { size_t page_count() const { return page_layouts_.size(); } // Gets the layout rectangle for a page. Only valid after computing a layout. - const pp::Rect& page_rect(size_t page_index) const { + const gfx::Rect& page_rect(size_t page_index) const { DCHECK_LT(page_index, page_count()); return page_layouts_[page_index].outer_rect; } // Gets the layout rectangle for a page's bounds (which excludes additional // regions like page shadows). Only valid after computing a layout. - const pp::Rect& page_bounds_rect(size_t page_index) const { + const gfx::Rect& page_bounds_rect(size_t page_index) const { DCHECK_LT(page_index, page_count()); return page_layouts_[page_index].inner_rect; } @@ -139,16 +135,16 @@ class DocumentLayout final { // Layout of a single page. struct PageLayout { // Bounding rectangle for the page with decorations. - pp::Rect outer_rect; + gfx::Rect outer_rect; // Bounding rectangle for the page without decorations. - pp::Rect inner_rect; + gfx::Rect inner_rect; }; // Copies |source_rect| to |destination_rect|, setting |dirty_| to true if // |destination_rect| is modified as a result. - void CopyRectIfModified(const pp::Rect& source_rect, - pp::Rect* destination_rect); + void CopyRectIfModified(const gfx::Rect& source_rect, + gfx::Rect& destination_rect); Options options_; diff --git a/chromium/pdf/document_layout_unittest.cc b/chromium/pdf/document_layout_unittest.cc index 350a95cd5a6..b65c1941ba6 100644 --- a/chromium/pdf/document_layout_unittest.cc +++ b/chromium/pdf/document_layout_unittest.cc @@ -5,6 +5,7 @@ #include "pdf/document_layout.h" #include "testing/gtest/include/gtest/gtest.h" +#include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/size.h" namespace chrome_pdf { @@ -21,13 +22,6 @@ class DocumentLayoutTest : public testing::Test { DocumentLayout layout_; }; -// TODO(kmoon): Need to use this with EXPECT_PRED2 instead of just using -// EXPECT_EQ, due to ADL issues with pp::Rect's operator== (defined in global -// namespace, instead of in "pp"). -inline bool PpRectEq(const pp::Rect& lhs, const pp::Rect& rhs) { - return lhs == rhs; -} - TEST_F(DocumentLayoutOptionsTest, DefaultConstructor) { EXPECT_EQ(options_.default_page_orientation(), PageOrientation::kOriginal); EXPECT_FALSE(options_.two_up_view_enabled()); @@ -194,38 +188,29 @@ TEST_F(DocumentLayoutTest, ComputeSingleViewLayout) { {300, 400}, {400, 500}, {300, 400}, {200, 300}}; layout_.ComputeSingleViewLayout(page_sizes); ASSERT_EQ(4u, layout_.page_count()); - EXPECT_PRED2(PpRectEq, pp::Rect(50, 0, 300, 400), layout_.page_rect(0)); - EXPECT_PRED2(PpRectEq, pp::Rect(0, 404, 400, 500), layout_.page_rect(1)); - EXPECT_PRED2(PpRectEq, pp::Rect(50, 908, 300, 400), layout_.page_rect(2)); - EXPECT_PRED2(PpRectEq, pp::Rect(100, 1312, 200, 300), layout_.page_rect(3)); - EXPECT_PRED2(PpRectEq, pp::Rect(55, 3, 290, 390), - layout_.page_bounds_rect(0)); - EXPECT_PRED2(PpRectEq, pp::Rect(5, 407, 390, 490), - layout_.page_bounds_rect(1)); - EXPECT_PRED2(PpRectEq, pp::Rect(55, 911, 290, 390), - layout_.page_bounds_rect(2)); - EXPECT_PRED2(PpRectEq, pp::Rect(105, 1315, 190, 290), - layout_.page_bounds_rect(3)); + EXPECT_EQ(gfx::Rect(50, 0, 300, 400), layout_.page_rect(0)); + EXPECT_EQ(gfx::Rect(0, 404, 400, 500), layout_.page_rect(1)); + EXPECT_EQ(gfx::Rect(50, 908, 300, 400), layout_.page_rect(2)); + EXPECT_EQ(gfx::Rect(100, 1312, 200, 300), layout_.page_rect(3)); + EXPECT_EQ(gfx::Rect(55, 3, 290, 390), layout_.page_bounds_rect(0)); + EXPECT_EQ(gfx::Rect(5, 407, 390, 490), layout_.page_bounds_rect(1)); + EXPECT_EQ(gfx::Rect(55, 911, 290, 390), layout_.page_bounds_rect(2)); + EXPECT_EQ(gfx::Rect(105, 1315, 190, 290), layout_.page_bounds_rect(3)); EXPECT_EQ(gfx::Size(400, 1612), layout_.size()); page_sizes = {{240, 300}, {320, 400}, {250, 360}, {300, 600}, {270, 555}}; layout_.ComputeSingleViewLayout(page_sizes); ASSERT_EQ(5u, layout_.page_count()); - EXPECT_PRED2(PpRectEq, pp::Rect(40, 0, 240, 300), layout_.page_rect(0)); - EXPECT_PRED2(PpRectEq, pp::Rect(0, 304, 320, 400), layout_.page_rect(1)); - EXPECT_PRED2(PpRectEq, pp::Rect(35, 708, 250, 360), layout_.page_rect(2)); - EXPECT_PRED2(PpRectEq, pp::Rect(10, 1072, 300, 600), layout_.page_rect(3)); - EXPECT_PRED2(PpRectEq, pp::Rect(25, 1676, 270, 555), layout_.page_rect(4)); - EXPECT_PRED2(PpRectEq, pp::Rect(45, 3, 230, 290), - layout_.page_bounds_rect(0)); - EXPECT_PRED2(PpRectEq, pp::Rect(5, 307, 310, 390), - layout_.page_bounds_rect(1)); - EXPECT_PRED2(PpRectEq, pp::Rect(40, 711, 240, 350), - layout_.page_bounds_rect(2)); - EXPECT_PRED2(PpRectEq, pp::Rect(15, 1075, 290, 590), - layout_.page_bounds_rect(3)); - EXPECT_PRED2(PpRectEq, pp::Rect(30, 1679, 260, 545), - layout_.page_bounds_rect(4)); + EXPECT_EQ(gfx::Rect(40, 0, 240, 300), layout_.page_rect(0)); + EXPECT_EQ(gfx::Rect(0, 304, 320, 400), layout_.page_rect(1)); + EXPECT_EQ(gfx::Rect(35, 708, 250, 360), layout_.page_rect(2)); + EXPECT_EQ(gfx::Rect(10, 1072, 300, 600), layout_.page_rect(3)); + EXPECT_EQ(gfx::Rect(25, 1676, 270, 555), layout_.page_rect(4)); + EXPECT_EQ(gfx::Rect(45, 3, 230, 290), layout_.page_bounds_rect(0)); + EXPECT_EQ(gfx::Rect(5, 307, 310, 390), layout_.page_bounds_rect(1)); + EXPECT_EQ(gfx::Rect(40, 711, 240, 350), layout_.page_bounds_rect(2)); + EXPECT_EQ(gfx::Rect(15, 1075, 290, 590), layout_.page_bounds_rect(3)); + EXPECT_EQ(gfx::Rect(30, 1679, 260, 545), layout_.page_bounds_rect(4)); EXPECT_EQ(gfx::Size(320, 2231), layout_.size()); } @@ -235,57 +220,44 @@ TEST_F(DocumentLayoutTest, ComputeTwoUpViewLayout) { {826, 1066}, {1066, 826}, {826, 1066}, {826, 900}}; layout_.ComputeTwoUpViewLayout(page_sizes); ASSERT_EQ(4u, layout_.page_count()); - EXPECT_PRED2(PpRectEq, pp::Rect(240, 0, 826, 1066), layout_.page_rect(0)); - EXPECT_PRED2(PpRectEq, pp::Rect(1066, 0, 1066, 826), layout_.page_rect(1)); - EXPECT_PRED2(PpRectEq, pp::Rect(240, 1066, 826, 1066), layout_.page_rect(2)); - EXPECT_PRED2(PpRectEq, pp::Rect(1066, 1066, 826, 900), layout_.page_rect(3)); - EXPECT_PRED2(PpRectEq, pp::Rect(245, 3, 820, 1056), - layout_.page_bounds_rect(0)); - EXPECT_PRED2(PpRectEq, pp::Rect(1067, 3, 1060, 816), - layout_.page_bounds_rect(1)); - EXPECT_PRED2(PpRectEq, pp::Rect(245, 1069, 820, 1056), - layout_.page_bounds_rect(2)); - EXPECT_PRED2(PpRectEq, pp::Rect(1067, 1069, 820, 890), - layout_.page_bounds_rect(3)); + EXPECT_EQ(gfx::Rect(240, 0, 826, 1066), layout_.page_rect(0)); + EXPECT_EQ(gfx::Rect(1066, 0, 1066, 826), layout_.page_rect(1)); + EXPECT_EQ(gfx::Rect(240, 1066, 826, 1066), layout_.page_rect(2)); + EXPECT_EQ(gfx::Rect(1066, 1066, 826, 900), layout_.page_rect(3)); + EXPECT_EQ(gfx::Rect(245, 3, 820, 1056), layout_.page_bounds_rect(0)); + EXPECT_EQ(gfx::Rect(1067, 3, 1060, 816), layout_.page_bounds_rect(1)); + EXPECT_EQ(gfx::Rect(245, 1069, 820, 1056), layout_.page_bounds_rect(2)); + EXPECT_EQ(gfx::Rect(1067, 1069, 820, 890), layout_.page_bounds_rect(3)); EXPECT_EQ(gfx::Size(2132, 2132), layout_.size()); // Test case where the widest page is on the left. page_sizes = {{1066, 826}, {820, 1056}, {820, 890}, {826, 1066}}; layout_.ComputeTwoUpViewLayout(page_sizes); ASSERT_EQ(4u, layout_.page_count()); - EXPECT_PRED2(PpRectEq, pp::Rect(0, 0, 1066, 826), layout_.page_rect(0)); - EXPECT_PRED2(PpRectEq, pp::Rect(1066, 0, 820, 1056), layout_.page_rect(1)); - EXPECT_PRED2(PpRectEq, pp::Rect(246, 1056, 820, 890), layout_.page_rect(2)); - EXPECT_PRED2(PpRectEq, pp::Rect(1066, 1056, 826, 1066), layout_.page_rect(3)); - EXPECT_PRED2(PpRectEq, pp::Rect(5, 3, 1060, 816), - layout_.page_bounds_rect(0)); - EXPECT_PRED2(PpRectEq, pp::Rect(1067, 3, 814, 1046), - layout_.page_bounds_rect(1)); - EXPECT_PRED2(PpRectEq, pp::Rect(251, 1059, 814, 880), - layout_.page_bounds_rect(2)); - EXPECT_PRED2(PpRectEq, pp::Rect(1067, 1059, 820, 1056), - layout_.page_bounds_rect(3)); + EXPECT_EQ(gfx::Rect(0, 0, 1066, 826), layout_.page_rect(0)); + EXPECT_EQ(gfx::Rect(1066, 0, 820, 1056), layout_.page_rect(1)); + EXPECT_EQ(gfx::Rect(246, 1056, 820, 890), layout_.page_rect(2)); + EXPECT_EQ(gfx::Rect(1066, 1056, 826, 1066), layout_.page_rect(3)); + EXPECT_EQ(gfx::Rect(5, 3, 1060, 816), layout_.page_bounds_rect(0)); + EXPECT_EQ(gfx::Rect(1067, 3, 814, 1046), layout_.page_bounds_rect(1)); + EXPECT_EQ(gfx::Rect(251, 1059, 814, 880), layout_.page_bounds_rect(2)); + EXPECT_EQ(gfx::Rect(1067, 1059, 820, 1056), layout_.page_bounds_rect(3)); EXPECT_EQ(gfx::Size(2132, 2122), layout_.size()); // Test case where there's an odd # of pages. page_sizes = {{200, 300}, {400, 200}, {300, 600}, {250, 500}, {300, 400}}; layout_.ComputeTwoUpViewLayout(page_sizes); ASSERT_EQ(5u, layout_.page_count()); - EXPECT_PRED2(PpRectEq, pp::Rect(200, 0, 200, 300), layout_.page_rect(0)); - EXPECT_PRED2(PpRectEq, pp::Rect(400, 0, 400, 200), layout_.page_rect(1)); - EXPECT_PRED2(PpRectEq, pp::Rect(100, 300, 300, 600), layout_.page_rect(2)); - EXPECT_PRED2(PpRectEq, pp::Rect(400, 300, 250, 500), layout_.page_rect(3)); - EXPECT_PRED2(PpRectEq, pp::Rect(100, 900, 300, 400), layout_.page_rect(4)); - EXPECT_PRED2(PpRectEq, pp::Rect(205, 3, 194, 290), - layout_.page_bounds_rect(0)); - EXPECT_PRED2(PpRectEq, pp::Rect(401, 3, 394, 190), - layout_.page_bounds_rect(1)); - EXPECT_PRED2(PpRectEq, pp::Rect(105, 303, 294, 590), - layout_.page_bounds_rect(2)); - EXPECT_PRED2(PpRectEq, pp::Rect(401, 303, 244, 490), - layout_.page_bounds_rect(3)); - EXPECT_PRED2(PpRectEq, pp::Rect(105, 903, 290, 390), - layout_.page_bounds_rect(4)); + EXPECT_EQ(gfx::Rect(200, 0, 200, 300), layout_.page_rect(0)); + EXPECT_EQ(gfx::Rect(400, 0, 400, 200), layout_.page_rect(1)); + EXPECT_EQ(gfx::Rect(100, 300, 300, 600), layout_.page_rect(2)); + EXPECT_EQ(gfx::Rect(400, 300, 250, 500), layout_.page_rect(3)); + EXPECT_EQ(gfx::Rect(100, 900, 300, 400), layout_.page_rect(4)); + EXPECT_EQ(gfx::Rect(205, 3, 194, 290), layout_.page_bounds_rect(0)); + EXPECT_EQ(gfx::Rect(401, 3, 394, 190), layout_.page_bounds_rect(1)); + EXPECT_EQ(gfx::Rect(105, 303, 294, 590), layout_.page_bounds_rect(2)); + EXPECT_EQ(gfx::Rect(401, 303, 244, 490), layout_.page_bounds_rect(3)); + EXPECT_EQ(gfx::Rect(105, 903, 290, 390), layout_.page_bounds_rect(4)); EXPECT_EQ(gfx::Size(800, 1300), layout_.size()); } diff --git a/chromium/pdf/document_loader_impl.cc b/chromium/pdf/document_loader_impl.cc index e0266bc1c89..3f403d08012 100644 --- a/chromium/pdf/document_loader_impl.cc +++ b/chromium/pdf/document_loader_impl.cc @@ -107,15 +107,6 @@ bool DocumentLoaderImpl::Init(std::unique_ptr<URLLoaderWrapper> loader, if (!loader_->IsContentEncoded()) chunk_stream_.set_eof_pos(std::max(0, loader_->GetContentLength())); - int64_t bytes_received = 0; - int64_t total_bytes_to_be_received = 0; - if (GetDocumentSize() == 0 && - loader_->GetDownloadProgress(&bytes_received, - &total_bytes_to_be_received)) { - chunk_stream_.set_eof_pos( - std::max(0, static_cast<int>(total_bytes_to_be_received))); - } - SetPartialLoadingEnabled( partial_loading_enabled_ && !base::StartsWith(url, "file://", base::CompareCase::INSENSITIVE_ASCII) && diff --git a/chromium/pdf/document_loader_impl_unittest.cc b/chromium/pdf/document_loader_impl_unittest.cc index 04f70bf7967..784fb207ba8 100644 --- a/chromium/pdf/document_loader_impl_unittest.cc +++ b/chromium/pdf/document_loader_impl_unittest.cc @@ -188,11 +188,6 @@ class TestURLLoader : public URLLoaderWrapper { data_->SetReadCallback(std::move(callback), buffer, buffer_size); } - bool GetDownloadProgress(int64_t* bytes_received, - int64_t* total_bytes_to_be_received) const override { - return false; - } - private: LoaderData* data_; }; diff --git a/chromium/pdf/draw_utils/coordinates.cc b/chromium/pdf/draw_utils/coordinates.cc index 6cdbfee5afc..c2a5f35dad8 100644 --- a/chromium/pdf/draw_utils/coordinates.cc +++ b/chromium/pdf/draw_utils/coordinates.cc @@ -8,19 +8,28 @@ #include <algorithm> #include "base/check_op.h" -#include "pdf/ppapi_migration/geometry_conversions.h" #include "ui/gfx/geometry/point.h" +#include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/size.h" namespace chrome_pdf { namespace draw_utils { -void AdjustBottomGapForRightSidePage(int page_x, pp::Rect* bottom_gap) { +IndexedPage::IndexedPage(int index, const gfx::Rect& rect) + : index(index), rect(rect) {} + +IndexedPage::IndexedPage(const IndexedPage& other) = default; + +IndexedPage& IndexedPage::operator=(const IndexedPage& other) = default; + +IndexedPage::~IndexedPage() = default; + +void AdjustBottomGapForRightSidePage(int page_x, gfx::Rect* bottom_gap) { bottom_gap->set_x(page_x); bottom_gap->set_width(bottom_gap->width() / 2); } -void CenterRectHorizontally(int doc_width, pp::Rect* rect) { +void CenterRectHorizontally(int doc_width, gfx::Rect* rect) { DCHECK_GE(doc_width, rect->width()); rect->set_x((doc_width - rect->width()) / 2); @@ -31,17 +40,17 @@ void ExpandDocumentSize(const gfx::Size& rect_size, gfx::Size* doc_size) { doc_size->Enlarge(width_diff, rect_size.height()); } -pp::Rect GetBottomGapBetweenRects(int page_rect_bottom, - const pp::Rect& bottom_rect) { +gfx::Rect GetBottomGapBetweenRects(int page_rect_bottom, + const gfx::Rect& bottom_rect) { if (page_rect_bottom >= bottom_rect.bottom()) - return pp::Rect(0, 0, 0, 0); + return gfx::Rect(0, 0, 0, 0); - return pp::Rect(bottom_rect.x(), page_rect_bottom, bottom_rect.width(), - bottom_rect.bottom() - page_rect_bottom); + return gfx::Rect(bottom_rect.x(), page_rect_bottom, bottom_rect.width(), + bottom_rect.bottom() - page_rect_bottom); } int GetMostVisiblePage(const std::vector<IndexedPage>& visible_pages, - const pp::Rect& visible_screen) { + const gfx::Rect& visible_screen) { if (visible_pages.empty()) return -1; @@ -53,7 +62,8 @@ int GetMostVisiblePage(const std::vector<IndexedPage>& visible_pages, if (page_area <= 0.0) continue; - pp::Rect screen_intersect = visible_screen.Intersect(visible_page.rect); + gfx::Rect screen_intersect = + gfx::IntersectRects(visible_screen, visible_page.rect); double intersect_area = static_cast<double>(screen_intersect.size().GetArea()) / page_area; if (intersect_area > most_visible_page_area) { @@ -83,80 +93,79 @@ PageInsetSizes GetPageInsetsForTwoUpView( return two_up_insets; } -pp::Rect GetRectForSingleView(const gfx::Size& rect_size, - const gfx::Size& document_size) { - pp::Rect page_rect({0, document_size.height()}, PPSizeFromSize(rect_size)); +gfx::Rect GetRectForSingleView(const gfx::Size& rect_size, + const gfx::Size& document_size) { + gfx::Rect page_rect({0, document_size.height()}, rect_size); CenterRectHorizontally(document_size.width(), &page_rect); return page_rect; } -pp::Rect GetScreenRect(const pp::Rect& rect, - const gfx::Point& position, - double zoom) { +gfx::Rect GetScreenRect(const gfx::Rect& rect, + const gfx::Point& position, + double zoom) { DCHECK_GT(zoom, 0); int x = static_cast<int>(rect.x() * zoom - position.x()); int y = static_cast<int>(rect.y() * zoom - position.y()); int right = static_cast<int>(ceil(rect.right() * zoom - position.x())); int bottom = static_cast<int>(ceil(rect.bottom() * zoom - position.y())); - return pp::Rect(x, y, right - x, bottom - y); + return gfx::Rect(x, y, right - x, bottom - y); } -pp::Rect GetSurroundingRect(int page_y, - int page_height, - const PageInsetSizes& inset_sizes, - int doc_width, - int bottom_separator) { - return pp::Rect( +gfx::Rect GetSurroundingRect(int page_y, + int page_height, + const PageInsetSizes& inset_sizes, + int doc_width, + int bottom_separator) { + return gfx::Rect( 0, page_y - inset_sizes.top, doc_width, page_height + inset_sizes.top + inset_sizes.bottom + bottom_separator); } -pp::Rect GetLeftFillRect(const pp::Rect& page_rect, - const PageInsetSizes& inset_sizes, - int bottom_separator) { +gfx::Rect GetLeftFillRect(const gfx::Rect& page_rect, + const PageInsetSizes& inset_sizes, + int bottom_separator) { DCHECK_GE(page_rect.x(), inset_sizes.left); - return pp::Rect(0, page_rect.y() - inset_sizes.top, - page_rect.x() - inset_sizes.left, - page_rect.height() + inset_sizes.top + inset_sizes.bottom + - bottom_separator); + return gfx::Rect(0, page_rect.y() - inset_sizes.top, + page_rect.x() - inset_sizes.left, + page_rect.height() + inset_sizes.top + inset_sizes.bottom + + bottom_separator); } -pp::Rect GetRightFillRect(const pp::Rect& page_rect, - const PageInsetSizes& inset_sizes, - int doc_width, - int bottom_separator) { +gfx::Rect GetRightFillRect(const gfx::Rect& page_rect, + const PageInsetSizes& inset_sizes, + int doc_width, + int bottom_separator) { int right_gap_x = page_rect.right() + inset_sizes.right; DCHECK_GE(doc_width, right_gap_x); - return pp::Rect(right_gap_x, page_rect.y() - inset_sizes.top, - doc_width - right_gap_x, - page_rect.height() + inset_sizes.top + inset_sizes.bottom + - bottom_separator); + return gfx::Rect(right_gap_x, page_rect.y() - inset_sizes.top, + doc_width - right_gap_x, + page_rect.height() + inset_sizes.top + inset_sizes.bottom + + bottom_separator); } -pp::Rect GetBottomFillRect(const pp::Rect& page_rect, - const PageInsetSizes& inset_sizes, - int bottom_separator) { - return pp::Rect(page_rect.x() - inset_sizes.left, - page_rect.bottom() + inset_sizes.bottom, - page_rect.width() + inset_sizes.left + inset_sizes.right, - bottom_separator); +gfx::Rect GetBottomFillRect(const gfx::Rect& page_rect, + const PageInsetSizes& inset_sizes, + int bottom_separator) { + return gfx::Rect(page_rect.x() - inset_sizes.left, + page_rect.bottom() + inset_sizes.bottom, + page_rect.width() + inset_sizes.left + inset_sizes.right, + bottom_separator); } -pp::Rect GetLeftRectForTwoUpView(const gfx::Size& rect_size, - const gfx::Point& position) { +gfx::Rect GetLeftRectForTwoUpView(const gfx::Size& rect_size, + const gfx::Point& position) { DCHECK_LE(rect_size.width(), position.x()); - return pp::Rect(position.x() - rect_size.width(), position.y(), - rect_size.width(), rect_size.height()); + return gfx::Rect(position.x() - rect_size.width(), position.y(), + rect_size.width(), rect_size.height()); } -pp::Rect GetRightRectForTwoUpView(const gfx::Size& rect_size, - const gfx::Point& position) { - return pp::Rect(position.x(), position.y(), rect_size.width(), - rect_size.height()); +gfx::Rect GetRightRectForTwoUpView(const gfx::Size& rect_size, + const gfx::Point& position) { + return gfx::Rect(position, rect_size); } } // namespace draw_utils diff --git a/chromium/pdf/draw_utils/coordinates.h b/chromium/pdf/draw_utils/coordinates.h index 613a8455686..3805c21036d 100644 --- a/chromium/pdf/draw_utils/coordinates.h +++ b/chromium/pdf/draw_utils/coordinates.h @@ -9,17 +9,13 @@ #include <vector> -#include "ppapi/cpp/rect.h" +#include "ui/gfx/geometry/rect.h" namespace gfx { class Point; class Size; } // namespace gfx -namespace pp { -class Point; -} - namespace chrome_pdf { namespace draw_utils { @@ -33,22 +29,27 @@ struct PageInsetSizes { int bottom; }; -// Struct for sending a page's pp::Rect object along with its corresponding +// Struct for sending a page's gfx::Rect object along with its corresponding // index in the PDF document. struct IndexedPage { + IndexedPage(int index, const gfx::Rect& rect); + IndexedPage(const IndexedPage& other); + IndexedPage& operator=(const IndexedPage& other); + ~IndexedPage(); + int index; - pp::Rect rect; + gfx::Rect rect; }; // Given a right page's |bottom_gap|, reduce it to only the part of |bottom_gap| // that is directly below the right page by translating |bottom_gap| to |page_x| // and halving its width. This avoids over-drawing empty space on the already // drawn left page and the empty space to the right of the page. -void AdjustBottomGapForRightSidePage(int page_x, pp::Rect* bottom_gap); +void AdjustBottomGapForRightSidePage(int page_x, gfx::Rect* bottom_gap); // Given |doc_width|, horizontally center |rect| within the document. // |doc_width| must be greater than or equal to |rect|. -void CenterRectHorizontally(int doc_width, pp::Rect* rect); +void CenterRectHorizontally(int doc_width, gfx::Rect* rect); // Given |rect_size|, sets the width of |doc_size| to the max of |rect_size|'s // width and |doc_size|'s width. Also adds the height of |rect_size| to @@ -56,11 +57,11 @@ void CenterRectHorizontally(int doc_width, pp::Rect* rect); void ExpandDocumentSize(const gfx::Size& rect_size, gfx::Size* doc_size); // Given |page_rect_bottom| and |bottom_rect| in the same coordinate space, -// return a pp::Rect object representing the portion of |bottom_rect| that is +// return a gfx::Rect object representing the portion of |bottom_rect| that is // below |page_rect_bottom|. Returns an empty rectangle if |page_rect_bottom| // is greater than or equal to |bottom_rect.bottom()|. -pp::Rect GetBottomGapBetweenRects(int page_rect_bottom, - const pp::Rect& bottom_rect); +gfx::Rect GetBottomGapBetweenRects(int page_rect_bottom, + const gfx::Rect& bottom_rect); // Given |visible_pages| and |visible_screen| in the same coordinates, return // the index of the page in |visible_pages| which has the largest proportion of @@ -68,7 +69,7 @@ pp::Rect GetBottomGapBetweenRects(int page_rect_bottom, // page with the lower index. Returns -1 if |visible_pages| is empty. Returns // first page in |visible_pages| if no page intersects with |visible_screen|. int GetMostVisiblePage(const std::vector<IndexedPage>& visible_pages, - const pp::Rect& visible_screen); + const gfx::Rect& visible_screen); // Given |page_index|, and |num_of_pages|, return the configuration of // |single_view_insets| and |horizontal_separator| for the current page in @@ -80,63 +81,63 @@ PageInsetSizes GetPageInsetsForTwoUpView( int horizontal_separator); // Given |rect_size| and |document_size| create a horizontally centered -// pp::Rect placed at the bottom of the current document. -pp::Rect GetRectForSingleView(const gfx::Size& rect_size, - const gfx::Size& document_size); +// gfx::Rect placed at the bottom of the current document. +gfx::Rect GetRectForSingleView(const gfx::Size& rect_size, + const gfx::Size& document_size); // Given |rect| in document coordinates, a |position| in screen coordinates, // and a |zoom| factor, returns the rectangle in screen coordinates (i.e. // 0,0 is top left corner of plugin area). An empty |rect| will always // result in an empty output rect. For |zoom|, a value of 1 means 100%. // |zoom| is never less than or equal to 0. -pp::Rect GetScreenRect(const pp::Rect& rect, - const gfx::Point& position, - double zoom); +gfx::Rect GetScreenRect(const gfx::Rect& rect, + const gfx::Point& position, + double zoom); // Given |page_y|, |page_height|, |inset_sizes|, |doc_width|, and // |bottom_separator| all in the same coordinate space, return the page and its // surrounding border areas and |bottom_separator|. This includes the sides if // the page is narrower than the document. -pp::Rect GetSurroundingRect(int page_y, - int page_height, - const PageInsetSizes& inset_sizes, - int doc_width, - int bottom_separator); +gfx::Rect GetSurroundingRect(int page_y, + int page_height, + const PageInsetSizes& inset_sizes, + int doc_width, + int bottom_separator); // Given |page_rect| in document coordinates, |inset_sizes|, and -// |bottom_separator|, return a pp::Rect object representing the gap on the +// |bottom_separator|, return a gfx::Rect object representing the gap on the // left side of the page created by insetting the page. I.e. the difference, // on the left side, between the initial |page_rect| and the |page_rect| inset // with |inset_sizes| (current value of |page_rect|). // The x coordinate of |page_rect| must be greater than or equal to // |inset_sizes.left|. -pp::Rect GetLeftFillRect(const pp::Rect& page_rect, - const PageInsetSizes& inset_sizes, - int bottom_separator); +gfx::Rect GetLeftFillRect(const gfx::Rect& page_rect, + const PageInsetSizes& inset_sizes, + int bottom_separator); // Same as GetLeftFillRect(), but for the right side of |page_rect| and also // depends on the |doc_width|. Additionally, |doc_width| must be greater than or // equal to the sum of |page_rect.right| and |inset_sizes.right|. -pp::Rect GetRightFillRect(const pp::Rect& page_rect, - const PageInsetSizes& inset_sizes, - int doc_width, - int bottom_separator); - -// Same as GetLeftFillRect(), but for the bottom side of |page_rect|. -pp::Rect GetBottomFillRect(const pp::Rect& page_rect, +gfx::Rect GetRightFillRect(const gfx::Rect& page_rect, const PageInsetSizes& inset_sizes, + int doc_width, int bottom_separator); -// Given |rect_size|, create a pp::Rect where the top-right corner lies at +// Same as GetLeftFillRect(), but for the bottom side of |page_rect|. +gfx::Rect GetBottomFillRect(const gfx::Rect& page_rect, + const PageInsetSizes& inset_sizes, + int bottom_separator); + +// Given |rect_size|, create a gfx::Rect where the top-right corner lies at // |position|. The width of |rect_size| must be less than or equal to the x // value for |position|. -pp::Rect GetLeftRectForTwoUpView(const gfx::Size& rect_size, - const gfx::Point& position); +gfx::Rect GetLeftRectForTwoUpView(const gfx::Size& rect_size, + const gfx::Point& position); -// Given |rect_size|, create a pp::Rect where the top-left corner lies at +// Given |rect_size|, create a gfx::Rect where the top-left corner lies at // |position|. -pp::Rect GetRightRectForTwoUpView(const gfx::Size& rect_size, - const gfx::Point& position); +gfx::Rect GetRightRectForTwoUpView(const gfx::Size& rect_size, + const gfx::Point& position); } // namespace draw_utils } // namespace chrome_pdf diff --git a/chromium/pdf/draw_utils/coordinates_unittest.cc b/chromium/pdf/draw_utils/coordinates_unittest.cc index 957e2858206..0628a2b4774 100644 --- a/chromium/pdf/draw_utils/coordinates_unittest.cc +++ b/chromium/pdf/draw_utils/coordinates_unittest.cc @@ -4,9 +4,9 @@ #include "pdf/draw_utils/coordinates.h" -#include "pdf/test/test_utils.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/gfx/geometry/point.h" +#include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/size.h" namespace chrome_pdf { @@ -31,31 +31,31 @@ void CompareInsetSizes(const PageInsetSizes& expected_insets, } // namespace TEST(CoordinateTest, AdjustBottomGapForRightSidePage) { - pp::Rect bottom_gap(0, 10, 500, 100); + gfx::Rect bottom_gap(0, 10, 500, 100); AdjustBottomGapForRightSidePage(250, &bottom_gap); - CompareRect({250, 10, 250, 100}, bottom_gap); + EXPECT_EQ(gfx::Rect(250, 10, 250, 100), bottom_gap); bottom_gap.SetRect(15, 20, 700, 100); AdjustBottomGapForRightSidePage(365, &bottom_gap); - CompareRect({365, 20, 350, 100}, bottom_gap); + EXPECT_EQ(gfx::Rect(365, 20, 350, 100), bottom_gap); bottom_gap.SetRect(100, 40, 951, 200); AdjustBottomGapForRightSidePage(450, &bottom_gap); - CompareRect({450, 40, 475, 200}, bottom_gap); + EXPECT_EQ(gfx::Rect(450, 40, 475, 200), bottom_gap); } TEST(CoordinateTest, CenterRectHorizontally) { - pp::Rect page_rect(10, 20, 400, 300); + gfx::Rect page_rect(10, 20, 400, 300); CenterRectHorizontally(600, &page_rect); - CompareRect({100, 20, 400, 300}, page_rect); + EXPECT_EQ(gfx::Rect(100, 20, 400, 300), page_rect); page_rect.SetRect(300, 450, 500, 700); CenterRectHorizontally(800, &page_rect); - CompareRect({150, 450, 500, 700}, page_rect); + EXPECT_EQ(gfx::Rect(150, 450, 500, 700), page_rect); page_rect.SetRect(800, 100, 200, 250); CenterRectHorizontally(350, &page_rect); - CompareRect({75, 100, 200, 250}, page_rect); + EXPECT_EQ(gfx::Rect(75, 100, 200, 250), page_rect); } TEST(CoordinateTest, ExpandDocumentSize) { @@ -80,18 +80,19 @@ TEST(CoordinateTest, ExpandDocumentSize) { } TEST(CoordinateTest, GetBottomGapBetweenRects) { - CompareRect({95, 600, 350, 50}, - GetBottomGapBetweenRects(600, {95, 200, 350, 450})); + EXPECT_EQ(gfx::Rect(95, 600, 350, 50), + GetBottomGapBetweenRects(600, {95, 200, 350, 450})); - CompareRect({200, 500, 350, 10}, - GetBottomGapBetweenRects(500, {200, 0, 350, 510})); + EXPECT_EQ(gfx::Rect(200, 500, 350, 10), + GetBottomGapBetweenRects(500, {200, 0, 350, 510})); // Test rectangle with a negative bottom value. - CompareRect({150, -100, 400, 150}, - GetBottomGapBetweenRects(-100, {150, 0, 400, 50})); + EXPECT_EQ(gfx::Rect(150, -100, 400, 150), + GetBottomGapBetweenRects(-100, {150, 0, 400, 50})); // Test case where |page_rect_bottom| >= |dirty_rect.bottom()|. - CompareRect({0, 0, 0, 0}, GetBottomGapBetweenRects(1400, {0, 10, 300, 500})); + EXPECT_EQ(gfx::Rect(0, 0, 0, 0), + GetBottomGapBetweenRects(1400, {0, 10, 300, 500})); } TEST(CoordinateTest, GetMostVisiblePage) { @@ -152,79 +153,83 @@ TEST(CoordinateTest, GetPageInsetsForTwoUpView) { TEST(CoordinateTest, GetRectForSingleView) { // Test portrait pages. - CompareRect({50, 500, 200, 400}, - GetRectForSingleView({200, 400}, {300, 500})); - CompareRect({50, 600, 100, 340}, - GetRectForSingleView({100, 340}, {200, 600})); + EXPECT_EQ(gfx::Rect(50, 500, 200, 400), + GetRectForSingleView({200, 400}, {300, 500})); + EXPECT_EQ(gfx::Rect(50, 600, 100, 340), + GetRectForSingleView({100, 340}, {200, 600})); // Test landscape pages. - CompareRect({0, 1000, 500, 450}, - GetRectForSingleView({500, 450}, {500, 1000})); - CompareRect({25, 1500, 650, 200}, - GetRectForSingleView({650, 200}, {700, 1500})); + EXPECT_EQ(gfx::Rect(0, 1000, 500, 450), + GetRectForSingleView({500, 450}, {500, 1000})); + EXPECT_EQ(gfx::Rect(25, 1500, 650, 200), + GetRectForSingleView({650, 200}, {700, 1500})); } TEST(CoordinateTest, GetScreenRect) { - const pp::Rect rect(10, 20, 200, 300); + const gfx::Rect rect(10, 20, 200, 300); // Test various zooms with the position at the origin. - CompareRect({10, 20, 200, 300}, GetScreenRect(rect, {0, 0}, 1)); - CompareRect({15, 30, 300, 450}, GetScreenRect(rect, {0, 0}, 1.5)); - CompareRect({5, 10, 100, 150}, GetScreenRect(rect, {0, 0}, 0.5)); + EXPECT_EQ(gfx::Rect(10, 20, 200, 300), GetScreenRect(rect, {0, 0}, 1)); + EXPECT_EQ(gfx::Rect(15, 30, 300, 450), GetScreenRect(rect, {0, 0}, 1.5)); + EXPECT_EQ(gfx::Rect(5, 10, 100, 150), GetScreenRect(rect, {0, 0}, 0.5)); // Test various zooms with the position elsewhere. - CompareRect({-390, -10, 200, 300}, GetScreenRect(rect, {400, 30}, 1)); - CompareRect({-385, 0, 300, 450}, GetScreenRect(rect, {400, 30}, 1.5)); - CompareRect({-395, -20, 100, 150}, GetScreenRect(rect, {400, 30}, 0.5)); + EXPECT_EQ(gfx::Rect(-390, -10, 200, 300), GetScreenRect(rect, {400, 30}, 1)); + EXPECT_EQ(gfx::Rect(-385, 0, 300, 450), GetScreenRect(rect, {400, 30}, 1.5)); + EXPECT_EQ(gfx::Rect(-395, -20, 100, 150), + GetScreenRect(rect, {400, 30}, 0.5)); // Test various zooms with a negative position. - CompareRect({-90, 70, 200, 300}, GetScreenRect(rect, {100, -50}, 1)); - CompareRect({-85, 80, 300, 450}, GetScreenRect(rect, {100, -50}, 1.5)); - CompareRect({-95, 60, 100, 150}, GetScreenRect(rect, {100, -50}, 0.5)); + EXPECT_EQ(gfx::Rect(-90, 70, 200, 300), GetScreenRect(rect, {100, -50}, 1)); + EXPECT_EQ(gfx::Rect(-85, 80, 300, 450), GetScreenRect(rect, {100, -50}, 1.5)); + EXPECT_EQ(gfx::Rect(-95, 60, 100, 150), GetScreenRect(rect, {100, -50}, 0.5)); // Test an empty rect always outputs an empty rect. - const pp::Rect empty_rect; - CompareRect({-20, -500, 0, 0}, GetScreenRect(empty_rect, {20, 500}, 1)); - CompareRect({-20, -500, 0, 0}, GetScreenRect(empty_rect, {20, 500}, 1.5)); - CompareRect({-20, -500, 0, 0}, GetScreenRect(empty_rect, {20, 500}, 0.5)); + const gfx::Rect empty_rect; + EXPECT_EQ(gfx::Rect(-20, -500, 0, 0), + GetScreenRect(empty_rect, {20, 500}, 1)); + EXPECT_EQ(gfx::Rect(-20, -500, 0, 0), + GetScreenRect(empty_rect, {20, 500}, 1.5)); + EXPECT_EQ(gfx::Rect(-20, -500, 0, 0), + GetScreenRect(empty_rect, {20, 500}, 0.5)); } TEST(CoordinateTest, GetSurroundingRect) { constexpr int kDocWidth = 1000; // Test various position, sizes, and document width. - CompareRect({0, 97, 1000, 314}, - GetSurroundingRect(100, 300, kSingleViewInsets, kDocWidth, - kBottomSeparator)); - CompareRect({0, 37, 1000, 214}, - GetSurroundingRect(40, 200, kSingleViewInsets, kDocWidth, - kBottomSeparator)); - CompareRect({0, 197, 1000, 514}, - GetSurroundingRect(200, 500, kSingleViewInsets, kDocWidth, - kBottomSeparator)); - CompareRect( - {0, -103, 200, 314}, + EXPECT_EQ(gfx::Rect(0, 97, 1000, 314), + GetSurroundingRect(100, 300, kSingleViewInsets, kDocWidth, + kBottomSeparator)); + EXPECT_EQ(gfx::Rect(0, 37, 1000, 214), + GetSurroundingRect(40, 200, kSingleViewInsets, kDocWidth, + kBottomSeparator)); + EXPECT_EQ(gfx::Rect(0, 197, 1000, 514), + GetSurroundingRect(200, 500, kSingleViewInsets, kDocWidth, + kBottomSeparator)); + EXPECT_EQ( + gfx::Rect(0, -103, 200, 314), GetSurroundingRect(-100, 300, kSingleViewInsets, 200, kBottomSeparator)); } TEST(CoordinateTest, GetLeftFillRect) { // Testing various rectangles with different positions and sizes. - pp::Rect page_rect(10, 20, 400, 500); - CompareRect({0, 17, 5, 514}, - GetLeftFillRect(page_rect, kSingleViewInsets, kBottomSeparator)); + gfx::Rect page_rect(10, 20, 400, 500); + EXPECT_EQ(gfx::Rect(0, 17, 5, 514), + GetLeftFillRect(page_rect, kSingleViewInsets, kBottomSeparator)); page_rect.SetRect(200, 300, 400, 350); - CompareRect({0, 297, 195, 364}, - GetLeftFillRect(page_rect, kSingleViewInsets, kBottomSeparator)); + EXPECT_EQ(gfx::Rect(0, 297, 195, 364), + GetLeftFillRect(page_rect, kSingleViewInsets, kBottomSeparator)); page_rect.SetRect(800, 650, 20, 15); - CompareRect({0, 647, 795, 29}, - GetLeftFillRect(page_rect, kSingleViewInsets, kBottomSeparator)); + EXPECT_EQ(gfx::Rect(0, 647, 795, 29), + GetLeftFillRect(page_rect, kSingleViewInsets, kBottomSeparator)); // Testing rectangle with a negative y-component. page_rect.SetRect(50, -200, 100, 300); - CompareRect({0, -203, 45, 314}, - GetLeftFillRect(page_rect, kSingleViewInsets, kBottomSeparator)); + EXPECT_EQ(gfx::Rect(0, -203, 45, 314), + GetLeftFillRect(page_rect, kSingleViewInsets, kBottomSeparator)); } TEST(CoordinateTest, GetRightFillRect) { @@ -232,66 +237,67 @@ TEST(CoordinateTest, GetRightFillRect) { // Testing various rectangles with different positions, sizes, and document // widths. - pp::Rect page_rect(10, 20, 400, 500); - CompareRect({415, 17, 585, 514}, - GetRightFillRect(page_rect, kSingleViewInsets, kDocWidth, - kBottomSeparator)); + gfx::Rect page_rect(10, 20, 400, 500); + EXPECT_EQ(gfx::Rect(415, 17, 585, 514), + GetRightFillRect(page_rect, kSingleViewInsets, kDocWidth, + kBottomSeparator)); page_rect.SetRect(200, 300, 400, 350); - CompareRect({605, 297, 395, 364}, - GetRightFillRect(page_rect, kSingleViewInsets, kDocWidth, - kBottomSeparator)); + EXPECT_EQ(gfx::Rect(605, 297, 395, 364), + GetRightFillRect(page_rect, kSingleViewInsets, kDocWidth, + kBottomSeparator)); page_rect.SetRect(200, 300, 400, 350); - CompareRect( - {605, 297, 195, 364}, + EXPECT_EQ( + gfx::Rect(605, 297, 195, 364), GetRightFillRect(page_rect, kSingleViewInsets, 800, kBottomSeparator)); // Testing rectangle with a negative y-component. page_rect.SetRect(50, -200, 100, 300); - CompareRect({155, -203, 845, 314}, - GetRightFillRect(page_rect, kSingleViewInsets, kDocWidth, - kBottomSeparator)); + EXPECT_EQ(gfx::Rect(155, -203, 845, 314), + GetRightFillRect(page_rect, kSingleViewInsets, kDocWidth, + kBottomSeparator)); } TEST(CoordinateTest, GetBottomFillRect) { // Testing various rectangles with different positions and sizes. - pp::Rect page_rect(10, 20, 400, 500); - CompareRect({5, 527, 410, 4}, GetBottomFillRect(page_rect, kSingleViewInsets, - kBottomSeparator)); + gfx::Rect page_rect(10, 20, 400, 500); + EXPECT_EQ(gfx::Rect(5, 527, 410, 4), + GetBottomFillRect(page_rect, kSingleViewInsets, kBottomSeparator)); page_rect.SetRect(200, 300, 400, 350); - CompareRect( - {195, 657, 410, 4}, - GetBottomFillRect(page_rect, kSingleViewInsets, kBottomSeparator)); + EXPECT_EQ(gfx::Rect(195, 657, 410, 4), + GetBottomFillRect(page_rect, kSingleViewInsets, kBottomSeparator)); page_rect.SetRect(800, 650, 20, 15); - CompareRect({795, 672, 30, 4}, GetBottomFillRect(page_rect, kSingleViewInsets, - kBottomSeparator)); + EXPECT_EQ(gfx::Rect(795, 672, 30, 4), + GetBottomFillRect(page_rect, kSingleViewInsets, kBottomSeparator)); // Testing rectangle with a negative y-component. page_rect.SetRect(50, -200, 100, 300); - CompareRect({45, 107, 110, 4}, GetBottomFillRect(page_rect, kSingleViewInsets, - kBottomSeparator)); + EXPECT_EQ(gfx::Rect(45, 107, 110, 4), + GetBottomFillRect(page_rect, kSingleViewInsets, kBottomSeparator)); } TEST(CoordinateTest, GetLeftRectForTwoUpView) { - CompareRect({100, 100, 200, 400}, - GetLeftRectForTwoUpView({200, 400}, {300, 100})); - CompareRect({0, 0, 300, 400}, GetLeftRectForTwoUpView({300, 400}, {300, 0})); + EXPECT_EQ(gfx::Rect(100, 100, 200, 400), + GetLeftRectForTwoUpView({200, 400}, {300, 100})); + EXPECT_EQ(gfx::Rect(0, 0, 300, 400), + GetLeftRectForTwoUpView({300, 400}, {300, 0})); // Test empty rect gets positioned. - CompareRect({100, 0, 0, 0}, GetLeftRectForTwoUpView({0, 0}, {100, 0})); + EXPECT_EQ(gfx::Rect(100, 0, 0, 0), GetLeftRectForTwoUpView({0, 0}, {100, 0})); } TEST(CoordinateTest, GetRightRectForTwoUpView) { - CompareRect({300, 100, 200, 400}, - GetRightRectForTwoUpView({200, 400}, {300, 100})); - CompareRect({300, 0, 300, 400}, - GetRightRectForTwoUpView({300, 400}, {300, 0})); + EXPECT_EQ(gfx::Rect(300, 100, 200, 400), + GetRightRectForTwoUpView({200, 400}, {300, 100})); + EXPECT_EQ(gfx::Rect(300, 0, 300, 400), + GetRightRectForTwoUpView({300, 400}, {300, 0})); // Test empty rect gets positioned. - CompareRect({100, 0, 0, 0}, GetRightRectForTwoUpView({0, 0}, {100, 0})); + EXPECT_EQ(gfx::Rect(100, 0, 0, 0), + GetRightRectForTwoUpView({0, 0}, {100, 0})); } } // namespace draw_utils diff --git a/chromium/pdf/draw_utils/shadow.cc b/chromium/pdf/draw_utils/shadow.cc index df451722893..456927e6543 100644 --- a/chromium/pdf/draw_utils/shadow.cc +++ b/chromium/pdf/draw_utils/shadow.cc @@ -10,8 +10,9 @@ #include <algorithm> #include "base/check_op.h" -#include "ppapi/cpp/rect.h" #include "third_party/skia/include/core/SkBitmap.h" +#include "ui/gfx/geometry/rect.h" +#include "ui/gfx/geometry/size.h" namespace chrome_pdf { namespace draw_utils { @@ -111,10 +112,10 @@ ShadowMatrix::~ShadowMatrix() = default; namespace { void PaintShadow(SkBitmap& image, - const pp::Rect& clip_rc, - const pp::Rect& shadow_rc, + const gfx::Rect& clip_rc, + const gfx::Rect& shadow_rc, const ShadowMatrix& matrix) { - pp::Rect draw_rc = shadow_rc.Intersect(clip_rc); + gfx::Rect draw_rc = gfx::IntersectRects(shadow_rc, clip_rc); if (draw_rc.IsEmpty()) return; @@ -145,32 +146,32 @@ void PaintShadow(SkBitmap& image, } // namespace void DrawShadow(SkBitmap& image, - const pp::Rect& shadow_rc, - const pp::Rect& object_rc, - const pp::Rect& clip_rc, + const gfx::Rect& shadow_rc, + const gfx::Rect& object_rc, + const gfx::Rect& clip_rc, const ShadowMatrix& matrix) { if (shadow_rc == object_rc) return; // Nothing to paint. // Fill top part. - pp::Rect rc(shadow_rc.point(), - pp::Size(shadow_rc.width(), object_rc.y() - shadow_rc.y())); - PaintShadow(image, rc.Intersect(clip_rc), shadow_rc, matrix); + gfx::Rect rc(shadow_rc.origin(), + gfx::Size(shadow_rc.width(), object_rc.y() - shadow_rc.y())); + PaintShadow(image, gfx::IntersectRects(rc, clip_rc), shadow_rc, matrix); // Fill bottom part. - rc = pp::Rect(shadow_rc.x(), object_rc.bottom(), shadow_rc.width(), - shadow_rc.bottom() - object_rc.bottom()); - PaintShadow(image, rc.Intersect(clip_rc), shadow_rc, matrix); + rc = gfx::Rect(shadow_rc.x(), object_rc.bottom(), shadow_rc.width(), + shadow_rc.bottom() - object_rc.bottom()); + PaintShadow(image, gfx::IntersectRects(rc, clip_rc), shadow_rc, matrix); // Fill left part. - rc = pp::Rect(shadow_rc.x(), object_rc.y(), object_rc.x() - shadow_rc.x(), - object_rc.height()); - PaintShadow(image, rc.Intersect(clip_rc), shadow_rc, matrix); + rc = gfx::Rect(shadow_rc.x(), object_rc.y(), object_rc.x() - shadow_rc.x(), + object_rc.height()); + PaintShadow(image, gfx::IntersectRects(rc, clip_rc), shadow_rc, matrix); // Fill right part. - rc = pp::Rect(object_rc.right(), object_rc.y(), - shadow_rc.right() - object_rc.right(), object_rc.height()); - PaintShadow(image, rc.Intersect(clip_rc), shadow_rc, matrix); + rc = gfx::Rect(object_rc.right(), object_rc.y(), + shadow_rc.right() - object_rc.right(), object_rc.height()); + PaintShadow(image, gfx::IntersectRects(rc, clip_rc), shadow_rc, matrix); } } // namespace draw_utils diff --git a/chromium/pdf/draw_utils/shadow.h b/chromium/pdf/draw_utils/shadow.h index 31fbe6298e5..1513c53bebe 100644 --- a/chromium/pdf/draw_utils/shadow.h +++ b/chromium/pdf/draw_utils/shadow.h @@ -11,9 +11,9 @@ class SkBitmap; -namespace pp { +namespace gfx { class Rect; -} // namespace pp +} // namespace gfx namespace chrome_pdf { namespace draw_utils { @@ -48,9 +48,9 @@ class ShadowMatrix { // object_rc - rectangle that drops the shadow // clip_rc - clipping region void DrawShadow(SkBitmap& image, - const pp::Rect& shadow_rc, - const pp::Rect& object_rc, - const pp::Rect& clip_rc, + const gfx::Rect& shadow_rc, + const gfx::Rect& object_rc, + const gfx::Rect& clip_rc, const ShadowMatrix& matrix); } // namespace draw_utils diff --git a/chromium/pdf/out_of_process_instance.cc b/chromium/pdf/out_of_process_instance.cc index afd9968aa24..133e6f7709a 100644 --- a/chromium/pdf/out_of_process_instance.cc +++ b/chromium/pdf/out_of_process_instance.cc @@ -6,6 +6,7 @@ #include <stddef.h> #include <stdint.h> +#include <string.h> #include <algorithm> // for min/max() #include <cmath> // for log() and pow() @@ -14,6 +15,7 @@ #include <utility> #include "base/auto_reset.h" +#include "base/bind.h" #include "base/callback.h" #include "base/feature_list.h" #include "base/logging.h" @@ -37,11 +39,13 @@ #include "pdf/ppapi_migration/bitmap.h" #include "pdf/ppapi_migration/geometry_conversions.h" #include "pdf/ppapi_migration/graphics.h" +#include "pdf/ppapi_migration/input_event_conversions.h" +#include "pdf/ppapi_migration/url_loader.h" #include "pdf/ppapi_migration/value_conversions.h" +#include "pdf/thumbnail.h" #include "ppapi/c/dev/ppb_cursor_control_dev.h" #include "ppapi/c/pp_errors.h" #include "ppapi/c/private/ppb_pdf.h" -#include "ppapi/c/trusted/ppb_url_loader_trusted.h" #include "ppapi/cpp/core.h" #include "ppapi/cpp/dev/memory_dev.h" #include "ppapi/cpp/dev/text_input_dev.h" @@ -55,7 +59,6 @@ #include "ppapi/cpp/rect.h" #include "ppapi/cpp/resource.h" #include "ppapi/cpp/size.h" -#include "ppapi/cpp/url_request_info.h" #include "ppapi/cpp/var_array.h" #include "ppapi/cpp/var_array_buffer.h" #include "ppapi/cpp/var_dictionary.h" @@ -117,6 +120,7 @@ constexpr char kJSProgressPercentage[] = "progress"; constexpr char kJSPreviewLoadedType[] = "printPreviewLoaded"; // Metadata constexpr char kJSMetadataType[] = "metadata"; +constexpr char kJSAttachments[] = "attachments"; constexpr char kJSBookmarks[] = "bookmarks"; constexpr char kJSTitle[] = "title"; constexpr char kJSCanSerializeDocument[] = "canSerializeDocument"; @@ -130,10 +134,9 @@ constexpr char kJSPrintType[] = "print"; // Save attachment (Page -> Plugin) constexpr char kJSSaveAttachmentType[] = "saveAttachment"; constexpr char kJSAttachmentIndex[] = "attachmentIndex"; -constexpr char kJSAttachmentToken[] = "attachmentToken"; // Save attachment data (Plugin -> Page) constexpr char kJSSaveAttachmentDataType[] = "saveAttachmentData"; -constexpr char kJSAttachmentDataToSave[] = "attachmentDataToSave"; +constexpr char kJSAttachmentDataToSave[] = "dataToSave"; // Save (Page -> Plugin) constexpr char kJSSaveType[] = "save"; constexpr char kJSToken[] = "token"; @@ -208,6 +211,7 @@ constexpr char kJSGetNamedDestination[] = "namedDestination"; // Reply with the page number of the named destination (Plugin -> Page) constexpr char kJSGetNamedDestinationReplyType[] = "getNamedDestinationReply"; constexpr char kJSNamedDestinationPageNumber[] = "pageNumber"; +constexpr char kJSNamedDestinationView[] = "namedDestinationView"; // Selecting text in document (Plugin -> Page) constexpr char kJSSetIsSelectingType[] = "setIsSelecting"; @@ -224,9 +228,18 @@ constexpr char kJSFieldFocus[] = "focused"; constexpr char kJSDocumentFocusChangedType[] = "documentFocusChanged"; constexpr char kJSDocumentHasFocus[] = "hasFocus"; +// Request the thumbnail image for a particular page (Page -> Plugin) +constexpr char kJSGetThumbnailType[] = "getThumbnail"; +constexpr char kJSGetThumbnailPage[] = "page"; +// Reply with the image data of the requested thumbnail (Plugin -> Page) +constexpr char kJSGetThumbnailReplyType[] = "getThumbnailReply"; +constexpr char kJSGetThumbnailImageData[] = "imageData"; +constexpr char kJSGetThumbnailWidth[] = "width"; +constexpr char kJSGetThumbnailHeight[] = "height"; + constexpr int kFindResultCooldownMs = 100; -// Do not save forms with over 100 MB. This cap should be kept in sync with and +// Do not save files with over 100 MB. This cap should be kept in sync with and // is also enforced in chrome/browser/resources/pdf/pdf_viewer.js. constexpr size_t kMaximumSavedFileSize = 100u * 1000u * 1000u; @@ -450,18 +463,18 @@ void ScalePoint(float scale, pp::Point* point) { point->set_y(static_cast<int>(point->y() * scale)); } -void ScaleRect(float scale, pp::Rect* rect) { - int left = static_cast<int>(floorf(rect->x() * scale)); - int top = static_cast<int>(floorf(rect->y() * scale)); - int right = static_cast<int>(ceilf((rect->x() + rect->width()) * scale)); - int bottom = static_cast<int>(ceilf((rect->y() + rect->height()) * scale)); - rect->SetRect(left, top, right - left, bottom - top); -} - bool IsSaveDataSizeValid(size_t size) { return size > 0 && size <= kMaximumSavedFileSize; } +PDFiumFormFiller::ScriptOption DefaultScriptOption() { +#if defined(PDF_ENABLE_XFA) + return PDFiumFormFiller::ScriptOption::kJavaScriptAndXFA; +#else // defined(PDF_ENABLE_XFA) + return PDFiumFormFiller::ScriptOption::kJavaScript; +#endif // defined(PDF_ENABLE_XFA) +} + } // namespace OutOfProcessInstance::OutOfProcessInstance(PP_Instance instance) @@ -519,7 +532,7 @@ bool OutOfProcessInstance::Init(uint32_t argc, text_input_ = std::make_unique<pp::TextInput_Dev>(this); - bool enable_javascript = true; + PDFiumFormFiller::ScriptOption script_option = DefaultScriptOption(); bool has_edits = false; const char* stream_url = nullptr; const char* original_url = nullptr; @@ -541,8 +554,10 @@ bool OutOfProcessInstance::Init(uint32_t argc, success = base::StringToInt(argv[i], &top_toolbar_height_in_viewport_coords_); } else if (strcmp(argn[i], "javascript") == 0) { - if (base::FeatureList::IsEnabled(features::kPdfHonorJsContentSettings)) - enable_javascript = (strcmp(argv[i], "allow") == 0); + if (base::FeatureList::IsEnabled(features::kPdfHonorJsContentSettings)) { + if (strcmp(argv[i], "allow") != 0) + script_option = PDFiumFormFiller::ScriptOption::kNoJavaScript; + } } else if (strcmp(argn[i], "has-edits") == 0) { has_edits = true; } @@ -556,7 +571,7 @@ bool OutOfProcessInstance::Init(uint32_t argc, if (!stream_url) stream_url = original_url; - InitializeEngine(enable_javascript); + InitializeEngine(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 @@ -615,6 +630,8 @@ void OutOfProcessInstance::HandleMessage(const pp::Var& message) { HandleGetSelectedTextMessage(dict); } else if (type == kJSGetNamedDestinationType) { HandleGetNamedDestinationMessage(dict); + } else if (type == kJSGetThumbnailType) { + HandleGetThumbnailMessage(dict); } else { NOTREACHED(); } @@ -665,7 +682,7 @@ bool OutOfProcessInstance::HandleInputEvent(const pp::InputEvent& event) { } } - if (engine()->HandleEvent(event_device_res)) + if (SendInputEventToEngine(event_device_res)) return true; // Middle click is used for scrolling and is handled by the container page. @@ -840,10 +857,10 @@ void OutOfProcessInstance::SendAccessibilityViewportInfo() { pp::PDF::SetAccessibilityViewportInfo(GetPluginInstance(), &viewport_info); } -void OutOfProcessInstance::SelectionChanged(const pp::Rect& left, - const pp::Rect& right) { - pp::Point l(left.point().x() + available_area_.x(), left.point().y()); - pp::Point r(right.x() + available_area_.x(), right.point().y()); +void OutOfProcessInstance::SelectionChanged(const gfx::Rect& left, + const gfx::Rect& right) { + pp::Point l(left.x() + available_area_.x(), left.y()); + pp::Point r(right.x() + available_area_.x(), right.y()); float inverse_scale = 1.0f / device_scale_; ScalePoint(inverse_scale, &l); @@ -1038,16 +1055,18 @@ void OutOfProcessInstance::OnPaint(const std::vector<gfx::Rect>& paint_rects, if (!pdf_rect.IsEmpty()) { pdf_rect.Offset(available_area_.x() * -1, 0); - std::vector<pp::Rect> pdf_ready; - std::vector<pp::Rect> pdf_pending; - engine()->Paint(pdf_rect, skia_image_data_, pdf_ready, pdf_pending); + std::vector<gfx::Rect> pdf_ready; + std::vector<gfx::Rect> pdf_pending; + engine()->Paint(RectFromPPRect(pdf_rect), skia_image_data_, pdf_ready, + pdf_pending); for (auto& ready_rect : pdf_ready) { - ready_rect.Offset(available_area_.point()); - ready->push_back(PaintReadyRect(ready_rect, image_data_)); + ready_rect.Offset(VectorFromPPPoint(available_area_.point())); + ready->push_back( + PaintReadyRect(PPRectFromRect(ready_rect), image_data_)); } for (auto& pending_rect : pdf_pending) { - pending_rect.Offset(available_area_.point()); - pending->push_back(RectFromPPRect(pending_rect)); + pending_rect.Offset(VectorFromPPPoint(available_area_.point())); + pending->push_back(pending_rect); } } @@ -1081,9 +1100,10 @@ void OutOfProcessInstance::OnPaint(const std::vector<gfx::Rect>& paint_rects, } } -void OutOfProcessInstance::DidOpen(int32_t result) { +void OutOfProcessInstance::DidOpen(std::unique_ptr<UrlLoader> loader, + int32_t result) { if (result == PP_OK) { - if (!engine()->HandleDocumentLoad(embed_loader_)) { + if (!engine()->HandleDocumentLoad(std::move(loader))) { document_load_state_ = LOAD_STATE_LOADING; DocumentLoadFailed(); } @@ -1092,13 +1112,13 @@ void OutOfProcessInstance::DidOpen(int32_t result) { } } -void OutOfProcessInstance::DidOpenPreview(int32_t result) { +void OutOfProcessInstance::DidOpenPreview(std::unique_ptr<UrlLoader> loader, + int32_t result) { if (result == PP_OK) { preview_client_ = std::make_unique<PreviewModeClient>(this); - preview_engine_ = - std::make_unique<PDFiumEngine>(preview_client_.get(), - /*enable_javascript=*/false); - preview_engine_->HandleDocumentLoad(embed_preview_loader_); + preview_engine_ = std::make_unique<PDFiumEngine>( + preview_client_.get(), PDFiumFormFiller::ScriptOption::kNoJavaScript); + preview_engine_->HandleDocumentLoad(std::move(loader)); } else { NOTREACHED(); } @@ -1125,6 +1145,28 @@ void OutOfProcessInstance::CalculateBackgroundParts() { background_parts_.push_back(part); } +pp::VarArray OutOfProcessInstance::GetDocumentAttachments() { + const std::vector<DocumentAttachmentInfo>& list = + engine()->GetDocumentAttachmentInfoList(); + pp::VarArray attachments; + attachments.SetLength(list.size()); + + for (size_t i = 0; i < list.size(); ++i) { + const DocumentAttachmentInfo& attachment_info = list[i]; + pp::VarDictionary dict; + dict.Set(pp::Var("name"), pp::Var(base::UTF16ToUTF8(attachment_info.name))); + // Set |size| to -1 to indicate that the attachment is too big to be + // downloaded. + int32_t size = attachment_info.size_bytes <= kMaximumSavedFileSize + ? static_cast<int32_t>(attachment_info.size_bytes) + : -1; + dict.Set(pp::Var("size"), pp::Var(size)); + dict.Set(pp::Var("readable"), pp::Var(attachment_info.is_readable)); + attachments.Set(i, dict); + } + return attachments; +} + int OutOfProcessInstance::GetDocumentPixelWidth() const { return static_cast<int>(ceil(document_size_.width() * zoom_ * device_scale_)); } @@ -1156,7 +1198,7 @@ void OutOfProcessInstance::ProposeDocumentLayout(const DocumentLayout& layout) { dimensions.Set(kJSLayoutOptions, VarFromValue(layout.options().ToValue())); pp::VarArray page_dimensions_array; for (size_t i = 0; i < layout.page_count(); ++i) { - const pp::Rect& page_rect = layout.page_rect(i); + const gfx::Rect& page_rect = layout.page_rect(i); pp::VarDictionary page_dimensions; page_dimensions.Set(kJSPageX, pp::Var(page_rect.x())); page_dimensions.Set(kJSPageY, pp::Var(page_rect.y())); @@ -1168,15 +1210,15 @@ void OutOfProcessInstance::ProposeDocumentLayout(const DocumentLayout& layout) { PostMessage(dimensions); } -void OutOfProcessInstance::Invalidate(const pp::Rect& rect) { +void OutOfProcessInstance::Invalidate(const gfx::Rect& rect) { if (in_paint_) { deferred_invalidates_.push_back(rect); return; } - pp::Rect offset_rect(rect); - offset_rect.Offset(available_area_.point()); - paint_manager_.InvalidateRect(RectFromPPRect(offset_rect)); + gfx::Rect offset_rect(rect); + offset_rect.Offset(VectorFromPPPoint(available_area_.point())); + paint_manager_.InvalidateRect(offset_rect); } void OutOfProcessInstance::DidScroll(const gfx::Vector2d& offset) { @@ -1266,12 +1308,14 @@ void OutOfProcessInstance::UpdateCursor(PP_CursorType_Dev cursor) { } void OutOfProcessInstance::UpdateTickMarks( - const std::vector<pp::Rect>& tickmarks) { + const std::vector<gfx::Rect>& tickmarks) { float inverse_scale = 1.0f / device_scale_; - std::vector<pp::Rect> scaled_tickmarks = tickmarks; - for (auto& tickmark : scaled_tickmarks) - ScaleRect(inverse_scale, &tickmark); - tickmarks_ = scaled_tickmarks; + tickmarks_.clear(); + tickmarks_.reserve(tickmarks.size()); + for (auto& tickmark : tickmarks) { + tickmarks_.emplace_back( + PPRectFromRect(gfx::ScaleToEnclosingRect(tickmark, inverse_scale))); + } } void OutOfProcessInstance::NotifyNumberOfFindResultsChanged(int total, @@ -1440,28 +1484,22 @@ void OutOfProcessInstance::Print() { void OutOfProcessInstance::SubmitForm(const std::string& url, const void* data, int length) { - pp::URLRequestInfo request(this); - request.SetURL(url); - request.SetMethod("POST"); - request.AppendDataToBody(reinterpret_cast<const char*>(data), length); + UrlRequest request; + request.url = url; + request.method = "POST"; + request.body.assign(static_cast<const char*>(data), length); - form_loader_ = CreateURLLoaderInternal(); - pp::CompletionCallback callback = - PPCompletionCallbackFromResultCallback(base::BindOnce( - &OutOfProcessInstance::FormDidOpen, weak_factory_.GetWeakPtr())); - int rv = form_loader_.Open(request, callback); - if (rv != PP_OK_COMPLETIONPENDING) - callback.Run(rv); + form_loader_ = CreateUrlLoaderInternal(); + form_loader_->Open(request, base::BindOnce(&OutOfProcessInstance::FormDidOpen, + weak_factory_.GetWeakPtr())); } void OutOfProcessInstance::FormDidOpen(int32_t result) { - // TODO: inform the user of success/failure. - if (result != PP_OK) { - LOG(ERROR) << "FormDidOpen failed: " << result; - } + // TODO(crbug.com/719344): Process response. + LOG_IF(ERROR, result != PP_OK) << "FormDidOpen failed: " << result; } -pp::URLLoader OutOfProcessInstance::CreateURLLoader() { +std::unique_ptr<UrlLoader> OutOfProcessInstance::CreateUrlLoader() { if (full_) { if (!did_call_start_loading_) { did_call_start_loading_ = true; @@ -1475,7 +1513,7 @@ pp::URLLoader OutOfProcessInstance::CreateURLLoader() { this, PP_CONTENT_RESTRICTION_SAVE | PP_CONTENT_RESTRICTION_PRINT); } - return CreateURLLoaderInternal(); + return CreateUrlLoaderInternal(); } std::vector<PDFEngine::Client::SearchStringResult> @@ -1615,6 +1653,16 @@ void OutOfProcessInstance::HandleGetNamedDestinationMessage( reply.Set(pp::Var(kJSNamedDestinationPageNumber), named_destination ? static_cast<int>(named_destination->page) : -1); reply.Set(pp::Var(kJSMessageId), dict.Get(pp::Var(kJSMessageId)).AsString()); + + // Handle named destination view. + if (named_destination && !named_destination->view.empty()) { + std::ostringstream view_stream; + view_stream << named_destination->view; + for (unsigned long i = 0; i < named_destination->num_params; ++i) + view_stream << "," << named_destination->params[i]; + + reply.Set(pp::Var(kJSNamedDestinationView), view_stream.str()); + } PostMessage(reply); } @@ -1645,6 +1693,22 @@ void OutOfProcessInstance::HandleGetSelectedTextMessage( PostMessage(reply); } +void OutOfProcessInstance::HandleGetThumbnailMessage( + const pp::VarDictionary& dict) { + if (!dict.Get(pp::Var(kJSGetThumbnailPage)).is_number() || + !dict.Get(pp::Var(kJSMessageId)).is_string()) { + NOTREACHED(); + return; + } + + const int page_index = dict.Get(pp::Var(kJSGetThumbnailPage)).AsInt(); + engine()->RequestThumbnail( + page_index, device_scale_, + base::BindOnce(&OutOfProcessInstance::SendThumbnail, + weak_factory_.GetWeakPtr(), + dict.Get(pp::Var(kJSMessageId)).AsString())); +} + void OutOfProcessInstance::HandleLoadPreviewPageMessage( const pp::VarDictionary& dict) { if (!(dict.Get(pp::Var(kJSPreviewPageUrl)).is_string() && @@ -1703,7 +1767,7 @@ void OutOfProcessInstance::HandleResetPrintPreviewModeMessage( document_load_state_ = LOAD_STATE_LOADING; LoadUrl(url_, /*is_print_preview=*/false); preview_engine_.reset(); - InitializeEngine(/*enable_javascript=*/false); + InitializeEngine(PDFiumFormFiller::ScriptOption::kNoJavaScript); engine()->SetGrayscale(dict.Get(pp::Var(kJSPrintPreviewGrayscale)).AsBool()); engine()->New(url_.c_str(), /*headers=*/nullptr); @@ -1712,7 +1776,7 @@ void OutOfProcessInstance::HandleResetPrintPreviewModeMessage( void OutOfProcessInstance::HandleSaveAttachmentMessage( const pp::VarDictionary& dict) { - if (!dict.Get(pp::Var(kJSAttachmentToken)).is_string() || + if (!dict.Get(pp::Var(kJSMessageId)).is_string() || !dict.Get(pp::Var(kJSAttachmentIndex)).is_int() || dict.Get(pp::Var(kJSAttachmentIndex)).AsInt() < 0) { NOTREACHED(); @@ -1723,14 +1787,14 @@ void OutOfProcessInstance::HandleSaveAttachmentMessage( const std::vector<DocumentAttachmentInfo>& list = engine()->GetDocumentAttachmentInfoList(); if (static_cast<size_t>(index) >= list.size() || !list[index].is_readable || - list[index].size_bytes == 0) { + !IsSaveDataSizeValid(list[index].size_bytes)) { NOTREACHED(); return; } pp::VarDictionary message; message.Set(kType, kJSSaveAttachmentDataType); - message.Set(kJSAttachmentToken, dict.Get(pp::Var(kJSAttachmentToken))); + message.Set(kJSMessageId, dict.Get(pp::Var(kJSMessageId))); // This will be overwritten if the save is successful. message.Set(kJSAttachmentDataToSave, pp::Var(pp::Var::Null())); @@ -1788,8 +1852,8 @@ void OutOfProcessInstance::HandleSetTwoUpViewMessage( void OutOfProcessInstance::HandleUpdateScrollMessage( const pp::VarDictionary& dict) { if (!base::FeatureList::IsEnabled(features::kPDFViewerUpdate) || - !dict.Get(pp::Var(kJSUpdateScrollX)).is_int() || - !dict.Get(pp::Var(kJSUpdateScrollY)).is_int()) { + !dict.Get(pp::Var(kJSUpdateScrollX)).is_number() || + !dict.Get(pp::Var(kJSUpdateScrollY)).is_number()) { NOTREACHED(); return; } @@ -1809,7 +1873,7 @@ void OutOfProcessInstance::HandleViewportMessage( pp::Var layout_options_var = dict.Get(kJSLayoutOptions); if (!layout_options_var.is_undefined()) { DocumentLayout::Options layout_options; - layout_options.FromVar(layout_options_var); + layout_options.FromValue(ValueFromVar(layout_options_var)); // TODO(crbug.com/1013800): Eliminate need to get document size from here. document_size_ = PPSizeFromSize(engine()->ApplyDocumentLayout(layout_options)); @@ -2068,34 +2132,13 @@ void OutOfProcessInstance::OnGeometryChanged(double old_zoom, SendAccessibilityViewportInfo(); } -void OutOfProcessInstance::LoadUrl(const std::string& url, - bool is_print_preview) { - pp::URLRequestInfo request(this); - request.SetURL(url); - request.SetMethod("GET"); - request.SetFollowRedirects(false); - - pp::URLLoader* loader = - is_print_preview ? &embed_preview_loader_ : &embed_loader_; - *loader = CreateURLLoaderInternal(); - pp::CompletionCallback callback = PPCompletionCallbackFromResultCallback( - base::BindOnce(is_print_preview ? &OutOfProcessInstance::DidOpenPreview - : &OutOfProcessInstance::DidOpen, - weak_factory_.GetWeakPtr())); - int rv = loader->Open(request, callback); - if (rv != PP_OK_COMPLETIONPENDING) - callback.Run(rv); +base::WeakPtr<PdfViewPluginBase> OutOfProcessInstance::GetWeakPtr() { + return weak_factory_.GetWeakPtr(); } -pp::URLLoader OutOfProcessInstance::CreateURLLoaderInternal() { - pp::URLLoader loader(this); - - const PPB_URLLoaderTrusted* trusted_interface = - reinterpret_cast<const PPB_URLLoaderTrusted*>( - pp::Module::Get()->GetBrowserInterface( - PPB_URLLOADERTRUSTED_INTERFACE)); - if (trusted_interface) - trusted_interface->GrantUniversalAccess(loader.pp_resource()); +std::unique_ptr<UrlLoader> OutOfProcessInstance::CreateUrlLoaderInternal() { + auto loader = std::make_unique<PepperUrlLoader>(this); + loader->GrantUniversalAccess(); return loader; } @@ -2209,6 +2252,8 @@ void OutOfProcessInstance::SendDocumentMetadata() { if (!base::TrimWhitespace(base::UTF8ToUTF16(title), base::TRIM_ALL).empty()) metadata_message.Set(pp::Var(kJSTitle), pp::Var(title)); + metadata_message.Set(pp::Var(kJSAttachments), GetDocumentAttachments()); + pp::VarArray bookmarks = engine()->GetBookmarks(); metadata_message.Set(pp::Var(kJSBookmarks), bookmarks); @@ -2227,6 +2272,25 @@ void OutOfProcessInstance::SendLoadingProgress(double percentage) { PostMessage(progress_message); } +void OutOfProcessInstance::SendThumbnail(const std::string& message_id, + Thumbnail thumbnail) { + pp::VarDictionary reply; + reply.Set(pp::Var(kType), pp::Var(kJSGetThumbnailReplyType)); + reply.Set(pp::Var(kJSMessageId), message_id); + + const SkBitmap& bitmap = thumbnail.bitmap(); + const size_t buffer_size = bitmap.computeByteSize(); + pp::VarArrayBuffer buffer(buffer_size); + memcpy(buffer.Map(), bitmap.getPixels(), buffer_size); + reply.Set(pp::Var(kJSGetThumbnailImageData), buffer); + buffer.Unmap(); + + reply.Set(pp::Var(kJSGetThumbnailWidth), bitmap.width()); + reply.Set(pp::Var(kJSGetThumbnailHeight), bitmap.height()); + + PostMessage(reply); +} + void OutOfProcessInstance::UserMetricsRecordAction(const std::string& action) { // TODO(raymes): Move this function to PPB_UMA_Private. pp::PDF::UserMetricsRecordAction(this, pp::Var(action)); @@ -2245,6 +2309,43 @@ pp::FloatPoint OutOfProcessInstance::BoundScrollOffsetToDocument( return pp::FloatPoint(x, y); } +bool OutOfProcessInstance::SendInputEventToEngine(const pp::InputEvent& event) { + switch (event.GetType()) { + case PP_INPUTEVENT_TYPE_MOUSEDOWN: + case PP_INPUTEVENT_TYPE_MOUSEUP: + case PP_INPUTEVENT_TYPE_MOUSEMOVE: + case PP_INPUTEVENT_TYPE_MOUSEENTER: + case PP_INPUTEVENT_TYPE_MOUSELEAVE: + return engine()->HandleEvent( + GetMouseInputEvent(pp::MouseInputEvent(event))); + case PP_INPUTEVENT_TYPE_RAWKEYDOWN: + case PP_INPUTEVENT_TYPE_KEYDOWN: + case PP_INPUTEVENT_TYPE_KEYUP: + case PP_INPUTEVENT_TYPE_CHAR: + return engine()->HandleEvent( + GetKeyboardInputEvent(pp::KeyboardInputEvent(event))); + case PP_INPUTEVENT_TYPE_TOUCHSTART: + case PP_INPUTEVENT_TYPE_TOUCHEND: + case PP_INPUTEVENT_TYPE_TOUCHMOVE: + case PP_INPUTEVENT_TYPE_TOUCHCANCEL: + return engine()->HandleEvent( + GetTouchInputEvent(pp::TouchInputEvent(event))); + case PP_INPUTEVENT_TYPE_WHEEL: + case PP_INPUTEVENT_TYPE_CONTEXTMENU: + case PP_INPUTEVENT_TYPE_IME_COMPOSITION_START: + case PP_INPUTEVENT_TYPE_IME_COMPOSITION_UPDATE: + case PP_INPUTEVENT_TYPE_IME_COMPOSITION_END: + case PP_INPUTEVENT_TYPE_IME_TEXT: + // These event types are not used in PDFiumEngine, so there are no + // functions to convert them from pp::InputEvent to + // chrome_pdf::InputEvent. As such just send a dummy NoneInputEvent + // instead. + return engine()->HandleEvent(NoneInputEvent()); + case PP_INPUTEVENT_TYPE_UNDEFINED: + return false; + } +} + template <typename T> void OutOfProcessInstance::HistogramEnumeration(const char* name, T sample) { if (IsPrintPreview()) @@ -2278,7 +2379,7 @@ void OutOfProcessInstance::OnPrint(int32_t /*unused_but_required*/) { void OutOfProcessInstance::InvalidateAfterPaintDone( int32_t /*unused_but_required*/) { DCHECK(!in_paint_); - for (const pp::Rect& rect : deferred_invalidates_) + for (const gfx::Rect& rect : deferred_invalidates_) Invalidate(rect); deferred_invalidates_.clear(); } diff --git a/chromium/pdf/out_of_process_instance.h b/chromium/pdf/out_of_process_instance.h index a1a48a4e080..2dd51287468 100644 --- a/chromium/pdf/out_of_process_instance.h +++ b/chromium/pdf/out_of_process_instance.h @@ -25,7 +25,6 @@ #include "ppapi/cpp/image_data.h" #include "ppapi/cpp/instance.h" #include "ppapi/cpp/private/find_private.h" -#include "ppapi/cpp/url_loader.h" #include "third_party/skia/include/core/SkBitmap.h" namespace gfx { @@ -44,6 +43,8 @@ namespace chrome_pdf { class Graphics; class PaintReadyRect; class PDFiumEngine; +class Thumbnail; +class UrlLoader; class OutOfProcessInstance : public PdfViewPluginBase, public pp::Instance, @@ -57,26 +58,26 @@ class OutOfProcessInstance : public PdfViewPluginBase, OutOfProcessInstance& operator=(const OutOfProcessInstance&) = delete; ~OutOfProcessInstance() override; - // pp::Instance implementation. + // pp::Instance: bool Init(uint32_t argc, const char* argn[], const char* argv[]) override; void HandleMessage(const pp::Var& message) override; bool HandleInputEvent(const pp::InputEvent& event) override; void DidChangeView(const pp::View& view) override; void DidChangeFocus(bool has_focus) override; - // pp::Find_Private implementation. + // pp::Find_Private: bool StartFind(const std::string& text, bool case_sensitive) override; void SelectFindResult(bool forward) override; void StopFind() override; - // pp::PaintManager::Client implementation. + // pp::PaintManager::Client: std::unique_ptr<Graphics> CreatePaintGraphics(const gfx::Size& size) override; bool BindPaintGraphics(Graphics& graphics) override; void OnPaint(const std::vector<gfx::Rect>& paint_rects, std::vector<PaintReadyRect>* ready, std::vector<gfx::Rect>* pending) override; - // pp::Printing_Dev implementation. + // pp::Printing_Dev: uint32_t QuerySupportedPrintOutputFormats() override; int32_t PrintBegin(const PP_PrintSettings_Dev& print_settings) override; pp::Resource PrintPages(const PP_PrintPageNumberRange_Dev* page_ranges, @@ -84,7 +85,7 @@ class OutOfProcessInstance : public PdfViewPluginBase, void PrintEnd() override; bool IsPrintScalingDisabled() override; - // pp::Private implementation. + // pp::Private: pp::Var GetLinkAtPosition(const pp::Point& point); void GetPrintPresetOptionsFromDocument(PP_PdfPrintPresetOptions_Dev* options); void EnableAccessibility(); @@ -105,12 +106,10 @@ class OutOfProcessInstance : public PdfViewPluginBase, const PP_PdfPrintSettings_Dev* pdf_print_settings); void FlushCallback(int32_t result); - void DidOpen(int32_t result); - void DidOpenPreview(int32_t result); - // PdfViewPluginBase implementation. + // PdfViewPluginBase: void ProposeDocumentLayout(const DocumentLayout& layout) override; - void Invalidate(const pp::Rect& rect) override; + void Invalidate(const gfx::Rect& rect) override; void DidScroll(const gfx::Vector2d& offset) override; void ScrollToX(int x_in_screen_coords) override; void ScrollToY(int y_in_screen_coords, bool compensate_for_toolbar) override; @@ -123,7 +122,7 @@ class OutOfProcessInstance : public PdfViewPluginBase, const float* y, const float* zoom) override; void UpdateCursor(PP_CursorType_Dev cursor) override; - void UpdateTickMarks(const std::vector<pp::Rect>& tickmarks) 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 NotifyTouchSelectionOccurred() override; @@ -144,7 +143,7 @@ class OutOfProcessInstance : public PdfViewPluginBase, void SubmitForm(const std::string& url, const void* data, int length) override; - pp::URLLoader CreateURLLoader() override; + std::unique_ptr<UrlLoader> CreateUrlLoader() override; std::vector<SearchStringResult> SearchString(const base::char16* string, const base::char16* term, bool case_sensitive) override; @@ -158,12 +157,12 @@ class OutOfProcessInstance : public PdfViewPluginBase, bool IsPrintPreview() override; uint32_t GetBackgroundColor() override; void IsSelectingChanged(bool is_selecting) override; - void SelectionChanged(const pp::Rect& left, const pp::Rect& right) override; + void SelectionChanged(const gfx::Rect& left, const gfx::Rect& right) override; void EnteredEditMode() override; float GetToolbarHeightInScreenCoords() override; void DocumentFocusChanged(bool document_has_focus) override; - // PreviewModeClient::Client implementation. + // PreviewModeClient::Client: void PreviewDocumentLoadComplete() override; void PreviewDocumentLoadFailed() override; @@ -175,6 +174,14 @@ class OutOfProcessInstance : public PdfViewPluginBase, // for testing. static std::string GetFileNameFromUrl(const std::string& url); + 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 DidOpenPreview(std::unique_ptr<UrlLoader> loader, + int32_t result) override; + private: // Message handlers. void HandleBackgroundColorChangedMessage(const pp::VarDictionary& dict); @@ -182,6 +189,7 @@ class OutOfProcessInstance : public PdfViewPluginBase, void HandleGetNamedDestinationMessage(const pp::VarDictionary& dict); void HandleGetPasswordCompleteMessage(const pp::VarDictionary& dict); void HandleGetSelectedTextMessage(const pp::VarDictionary& dict); + void HandleGetThumbnailMessage(const pp::VarDictionary& dict); void HandleLoadPreviewPageMessage(const pp::VarDictionary& dict); void HandleResetPrintPreviewModeMessage(const pp::VarDictionary& dict); void HandleSaveAttachmentMessage(const pp::VarDictionary& dict); @@ -203,6 +211,14 @@ class OutOfProcessInstance : public PdfViewPluginBase, // aren't painted by the PDF engine). void CalculateBackgroundParts(); + // Returns a VarArray of Attachments. Each Attachment is a VarDictionary + // which contains the following key/values: + // - "name" - a string Var. + // - "size" - an int Var (-1 indicates the attachment file is too big to be + // downloaded). + // - "readable" a bool Var. + pp::VarArray GetDocumentAttachments(); + // Computes document width/height in device pixels, based on current zoom and // device scale int GetDocumentPixelWidth() const; @@ -211,12 +227,6 @@ class OutOfProcessInstance : public PdfViewPluginBase, // Draws a rectangle with the specified dimensions and color in our buffer. void FillRect(const pp::Rect& rect, uint32_t color); - void LoadUrl(const std::string& url, bool is_print_preview); - - // Creates a URL loader and allows it to access all urls, i.e. not just the - // frame's origin. - pp::URLLoader CreateURLLoaderInternal(); - bool CanSaveEdits() const; void SaveToFile(const std::string& token); void SaveToBuffer(const std::string& token); @@ -272,13 +282,16 @@ class OutOfProcessInstance : public PdfViewPluginBase, // Send a notification that the print preview has loaded. void SendPrintPreviewLoadedNotification(); - // Send document metadata. (e.g. PDF title and bookmarks.) + // Send document metadata. (e.g. PDF title, attachments and bookmarks.) void SendDocumentMetadata(); // Send the loading progress, where |percentage| represents the progress, or // -1 for loading error. void SendLoadingProgress(double percentage); + // Sends the thumbnail image data. + void SendThumbnail(const std::string& message_id, Thumbnail thumbnail); + // Bound the given scroll offset to the document. pp::FloatPoint BoundScrollOffsetToDocument( const pp::FloatPoint& scroll_offset); @@ -322,14 +335,13 @@ class OutOfProcessInstance : public PdfViewPluginBase, // Callback to do invalidation after painting finishes. void InvalidateAfterPaintDone(int32_t /*unused_but_required*/); + // Helper for HandleInputEvent(). Returns whether engine() handled the event + // or not. + bool SendInputEventToEngine(const pp::InputEvent& event); + pp::ImageData image_data_; SkBitmap skia_image_data_; // Must be kept in sync with |image_data_|. - // Used when the plugin is embedded in a page and we have to create the loader - // ourself. - pp::URLLoader embed_loader_; - pp::URLLoader embed_preview_loader_; - // The current cursor. PP_CursorType_Dev cursor_ = PP_CURSORTYPE_POINTER; @@ -380,7 +392,7 @@ class OutOfProcessInstance : public PdfViewPluginBase, // Whether OnPaint() is in progress or not. bool in_paint_ = false; // Deferred invalidates while |in_paint_| is true. - std::vector<pp::Rect> deferred_invalidates_; + std::vector<gfx::Rect> deferred_invalidates_; struct BackgroundPart { pp::Rect location; @@ -422,7 +434,7 @@ class OutOfProcessInstance : public PdfViewPluginBase, std::string url_; // Used for submitting forms. - pp::URLLoader form_loader_; + std::unique_ptr<UrlLoader> form_loader_; // The callback for receiving the password from the page. base::OnceCallback<void(const std::string&)> password_callback_; diff --git a/chromium/pdf/pdf.cc b/chromium/pdf/pdf.cc index ac143f1f12e..08468673f12 100644 --- a/chromium/pdf/pdf.cc +++ b/chromium/pdf/pdf.cc @@ -10,6 +10,8 @@ #include "pdf/pdf_engine.h" #include "pdf/pdf_init.h" +#include "ui/gfx/geometry/rect.h" +#include "ui/gfx/geometry/size_f.h" namespace chrome_pdf { @@ -18,7 +20,7 @@ namespace { class ScopedSdkInitializer { public: explicit ScopedSdkInitializer(bool enable_v8) { - if (!IsSDKInitializedViaPepper()) + if (!IsSDKInitializedViaPlugin()) InitializeSDK(enable_v8); } @@ -26,7 +28,7 @@ class ScopedSdkInitializer { ScopedSdkInitializer& operator=(const ScopedSdkInitializer&) = delete; ~ScopedSdkInitializer() { - if (!IsSDKInitializedViaPepper()) + if (!IsSDKInitializedViaPlugin()) ShutdownSDK(); } }; @@ -60,10 +62,10 @@ bool RenderPDFPageToDC(base::span<const uint8_t> pdf_buffer, ScopedSdkInitializer scoped_sdk_initializer(/*enable_v8=*/true); PDFEngineExports* engine_exports = PDFEngineExports::Get(); PDFEngineExports::RenderingSettings settings( - dpi_x, dpi_y, - pp::Rect(bounds_origin_x, bounds_origin_y, bounds_width, bounds_height), + gfx::Size(dpi_x, dpi_y), + gfx::Rect(bounds_origin_x, bounds_origin_y, bounds_width, bounds_height), fit_to_bounds, stretch_to_bounds, keep_aspect_ratio, center_in_bounds, - autorotate, use_color); + autorotate, use_color, /*render_for_printing=*/true); return engine_exports->RenderPDFPageToDC(pdf_buffer, page_number, settings, dc); } @@ -84,7 +86,7 @@ void SetPDFUsePrintMode(int mode) { bool GetPDFDocInfo(base::span<const uint8_t> pdf_buffer, int* page_count, - double* max_page_width) { + float* max_page_width) { ScopedSdkInitializer scoped_sdk_initializer(/*enable_v8=*/true); PDFEngineExports* engine_exports = PDFEngineExports::Get(); return engine_exports->GetPDFDocInfo(pdf_buffer, page_count, max_page_width); @@ -103,34 +105,29 @@ base::Value GetPDFStructTreeForPage(base::span<const uint8_t> pdf_buffer, return engine_exports->GetPDFStructTreeForPage(pdf_buffer, page_index); } -bool GetPDFPageSizeByIndex(base::span<const uint8_t> pdf_buffer, - int page_number, - double* width, - double* height) { +base::Optional<gfx::SizeF> GetPDFPageSizeByIndex( + base::span<const uint8_t> pdf_buffer, + int page_number) { ScopedSdkInitializer scoped_sdk_initializer(/*enable_v8=*/true); chrome_pdf::PDFEngineExports* engine_exports = chrome_pdf::PDFEngineExports::Get(); - return engine_exports->GetPDFPageSizeByIndex(pdf_buffer, page_number, width, - height); + return engine_exports->GetPDFPageSizeByIndex(pdf_buffer, page_number); } bool RenderPDFPageToBitmap(base::span<const uint8_t> pdf_buffer, int page_number, void* bitmap_buffer, - int bitmap_width, - int bitmap_height, - int dpi_x, - int dpi_y, - bool stretch_to_bounds, - bool keep_aspect_ratio, - bool autorotate, - bool use_color) { + const gfx::Size& bitmap_size, + const gfx::Size& dpi, + const RenderOptions& options) { ScopedSdkInitializer scoped_sdk_initializer(/*enable_v8=*/true); PDFEngineExports* engine_exports = PDFEngineExports::Get(); PDFEngineExports::RenderingSettings settings( - dpi_x, dpi_y, pp::Rect(bitmap_width, bitmap_height), - /*fit_to_bounds=*/true, stretch_to_bounds, keep_aspect_ratio, - /*center_in_bounds=*/true, autorotate, use_color); + dpi, gfx::Rect(bitmap_size), + /*fit_to_bounds=*/true, options.stretch_to_bounds, + options.keep_aspect_ratio, + /*center_in_bounds=*/true, options.autorotate, options.use_color, + options.render_device_type == RenderDeviceType::kPrinter); return engine_exports->RenderPDFPageToBitmap(pdf_buffer, page_number, settings, bitmap_buffer); } diff --git a/chromium/pdf/pdf.h b/chromium/pdf/pdf.h index 66da00699b3..56a97d4e5a3 100644 --- a/chromium/pdf/pdf.h +++ b/chromium/pdf/pdf.h @@ -25,6 +25,7 @@ typedef void (*PDFEnsureTypefaceCharactersAccessible)(const LOGFONT* font, namespace gfx { class Rect; class Size; +class SizeF; } // namespace gfx namespace chrome_pdf { @@ -103,7 +104,7 @@ void SetPDFUsePrintMode(int mode); // Returns false if the document is not valid. bool GetPDFDocInfo(base::span<const uint8_t> pdf_buffer, int* page_count, - double* max_page_width); + float* max_page_width); // Whether the PDF is Tagged (see 10.7 "Tagged PDF" in PDF Reference 1.7). // Returns true if it's a tagged (accessible) PDF, false if it's a valid @@ -120,41 +121,46 @@ base::Value GetPDFStructTreeForPage(base::span<const uint8_t> pdf_buffer, // rendered. // |page_number| is the page number that the function will get the dimensions // of. -// |width| is the output for the width of the page in points. -// |height| is the output for the height of the page in points. -// Returns false if the document or the page number are not valid. -bool GetPDFPageSizeByIndex(base::span<const uint8_t> pdf_buffer, - int page_number, - double* width, - double* height); +// Returns the size of the page in points, or nullopt if the document or the +// page number are not valid. +base::Optional<gfx::SizeF> GetPDFPageSizeByIndex( + base::span<const uint8_t> pdf_buffer, + int page_number); + +enum class RenderDeviceType { + kDisplay, + kPrinter, +}; + +struct RenderOptions { + // Whether the output should be stretched to fit the supplied bitmap. + bool stretch_to_bounds; + // If any scaling is needed, whether the original aspect ratio of the page is + // preserved while scaling. + bool keep_aspect_ratio; + // Whether the final image should be rotated to match the output bound. + bool autorotate; + // Specifies color or grayscale. + bool use_color; + // What type of device to render for. + RenderDeviceType render_device_type; +}; // Renders PDF page into 4-byte per pixel BGRA color bitmap. // |pdf_buffer| is the buffer that contains the entire PDF document to be // rendered. // |page_number| is the 0-based index of the page to be rendered. // |bitmap_buffer| is the output buffer for bitmap. -// |bitmap_width| is the width of the output bitmap. -// |bitmap_height| is the height of the output bitmap. -// |dpi_x| and |dpi_y| is the resolution. -// |stretch_to_bounds| specifies whether the output should be stretched to fit -// the supplied |bitmap_width| and |bitmap_height|. -// |keep_aspect_ratio| If any scaling is needed, this parameter specifies -// whether the original aspect ratio of the page is preserved while scaling. -// |autorotate| specifies whether the final image should be rotated to match -// the output bound. -// |use_color| specifies color or grayscale. +// |bitmap_size| is the size of the output bitmap. +// |dpi| is the 2D resolution. +// |options| is the options to render with. // Returns false if the document or the page number are not valid. bool RenderPDFPageToBitmap(base::span<const uint8_t> pdf_buffer, int page_number, void* bitmap_buffer, - int bitmap_width, - int bitmap_height, - int dpi_x, - int dpi_y, - bool stretch_to_bounds, - bool keep_aspect_ratio, - bool autorotate, - bool use_color); + const gfx::Size& bitmap_size, + const gfx::Size& dpi, + const RenderOptions& options); // Convert multiple PDF pages into a N-up PDF. // |input_buffers| is the vector of buffers with each buffer contains a PDF. diff --git a/chromium/pdf/pdf_engine.h b/chromium/pdf/pdf_engine.h index 5967a3970da..2c5aab0ff49 100644 --- a/chromium/pdf/pdf_engine.h +++ b/chromium/pdf/pdf_engine.h @@ -7,6 +7,7 @@ #include <stdint.h> +#include <memory> #include <string> #include <vector> @@ -20,15 +21,14 @@ #include "pdf/document_layout.h" #include "ppapi/c/dev/pp_cursor_type_dev.h" #include "ppapi/c/dev/ppp_printing_dev.h" -#include "ppapi/c/ppb_input_event.h" #include "ppapi/cpp/completion_callback.h" #include "ppapi/cpp/private/pdf.h" -#include "ppapi/cpp/rect.h" -#include "ppapi/cpp/size.h" #include "ppapi/cpp/url_loader.h" #include "ppapi/cpp/var_array.h" #include "ui/base/window_open_disposition.h" #include "ui/gfx/geometry/point_f.h" +#include "ui/gfx/geometry/rect.h" +#include "ui/gfx/geometry/rect_f.h" #if defined(OS_WIN) #include <windows.h> @@ -48,19 +48,24 @@ namespace gfx { class Point; class Rect; class Size; +class SizeF; class Vector2d; } // namespace gfx namespace pp { -class InputEvent; class VarDictionary; } // namespace pp namespace chrome_pdf { +class InputEvent; +class Thumbnail; +class UrlLoader; struct DocumentAttachmentInfo; struct DocumentMetadata; +using SendThumbnailCallback = base::OnceCallback<void(Thumbnail)>; + // Do one time initialization of the SDK. // If |enable_v8| is false, then the PDFEngine will not be able to run // JavaScript. @@ -132,7 +137,7 @@ class PDFEngine { virtual void ProposeDocumentLayout(const DocumentLayout& layout) = 0; // Informs the client that the given rect needs to be repainted. - virtual void Invalidate(const pp::Rect& rect) {} + virtual void Invalidate(const gfx::Rect& rect) {} // Informs the client to scroll the plugin area by the given offset. virtual void DidScroll(const gfx::Vector2d& offset) {} @@ -167,7 +172,7 @@ class PDFEngine { virtual void UpdateCursor(PP_CursorType_Dev cursor) {} // Updates the tick marks in the vertical scrollbar. - virtual void UpdateTickMarks(const std::vector<pp::Rect>& tickmarks) {} + virtual void UpdateTickMarks(const std::vector<gfx::Rect>& tickmarks) {} // Updates the number of find results for the current search term. If // there are no matches 0 should be passed in. Only when the plugin has @@ -220,7 +225,7 @@ class PDFEngine { int length) {} // Creates and returns new URL loader for partial document requests. - virtual pp::URLLoader CreateURLLoader() = 0; + virtual std::unique_ptr<UrlLoader> CreateUrlLoader() = 0; // Searches the given string for "term" and returns the results. Unicode- // aware. @@ -260,8 +265,8 @@ class PDFEngine { // Sets selection status. virtual void IsSelectingChanged(bool is_selecting) {} - virtual void SelectionChanged(const pp::Rect& left, const pp::Rect& right) { - } + virtual void SelectionChanged(const gfx::Rect& left, + const gfx::Rect& right) {} // Notifies the client that the PDF has been edited. virtual void EnteredEditMode() {} @@ -282,7 +287,7 @@ class PDFEngine { std::string url; int start_char_index; int char_count; - pp::FloatRect bounds; + gfx::RectF bounds; }; struct AccessibilityImageInfo { @@ -291,7 +296,7 @@ class PDFEngine { ~AccessibilityImageInfo(); std::string alt_text; - pp::FloatRect bounds; + gfx::RectF bounds; }; struct AccessibilityHighlightInfo { @@ -301,7 +306,7 @@ class PDFEngine { int start_char_index = -1; int char_count; - pp::FloatRect bounds; + gfx::RectF bounds; uint32_t color; std::string note_text; }; @@ -316,7 +321,7 @@ class PDFEngine { bool is_read_only; bool is_required; bool is_password; - pp::FloatRect bounds; + gfx::RectF bounds; }; virtual ~PDFEngine() {} @@ -331,13 +336,13 @@ class PDFEngine { // Paint is called a series of times. Before these n calls are made, PrePaint // is called once. After Paint is called n times, PostPaint is called once. virtual void PrePaint() = 0; - virtual void Paint(const pp::Rect& rect, + virtual void Paint(const gfx::Rect& rect, SkBitmap& image_data, - std::vector<pp::Rect>& ready, - std::vector<pp::Rect>& pending) = 0; + std::vector<gfx::Rect>& ready, + std::vector<gfx::Rect>& pending) = 0; virtual void PostPaint() = 0; - virtual bool HandleDocumentLoad(const pp::URLLoader& loader) = 0; - virtual bool HandleEvent(const pp::InputEvent& event) = 0; + virtual bool HandleDocumentLoad(std::unique_ptr<UrlLoader> loader) = 0; + virtual bool HandleEvent(const InputEvent& event) = 0; virtual uint32_t QuerySupportedPrintOutputFormats() = 0; virtual void PrintBegin() = 0; virtual pp::Resource PrintPages( @@ -404,12 +409,12 @@ class PDFEngine { // Gets the index of the most visible page, or -1 if none are visible. virtual int GetMostVisiblePage() = 0; // Gets the rectangle of the page not including the shadow. - virtual pp::Rect GetPageBoundsRect(int index) = 0; + virtual gfx::Rect GetPageBoundsRect(int index) = 0; // Gets the rectangle of the page excluding any additional areas. - virtual pp::Rect GetPageContentsRect(int index) = 0; + virtual gfx::Rect GetPageContentsRect(int index) = 0; // Returns a page's rect in screen coordinates, as well as its surrounding // border areas and bottom separator. - virtual pp::Rect GetPageScreenRect(int page_index) const = 0; + virtual gfx::Rect GetPageScreenRect(int page_index) const = 0; // Gets the offset of the vertical scrollbar from the top in document // coordinates. virtual int GetVerticalScrollbarYPosition() = 0; @@ -418,7 +423,7 @@ class PDFEngine { // Get the number of characters on a given page. virtual int GetCharCount(int page_index) = 0; // Get the bounds in page pixels of a character on a given page. - virtual pp::FloatRect GetCharBounds(int page_index, int char_index) = 0; + virtual gfx::RectF GetCharBounds(int page_index, int char_index) = 0; // Get a given unicode character on a given page. virtual uint32_t GetCharUnicode(int page_index, int char_index) = 0; // Given a start char index, find the longest continuous run of text that's @@ -452,8 +457,8 @@ class PDFEngine { // Returns true if all the pages are the same size. virtual bool GetPageSizeAndUniformity(gfx::Size* size) = 0; - // Returns a VarArray of Bookmarks, each a VarDictionary containing the - // following key/values: + // Returns a VarArray of Bookmarks. Each Bookmark is a VarDictionary + // which contains the following key/values: // - "title" - a string Var. // - "page" - an int Var. // - "children" - a VarArray(), with each entry containing a VarDictionary of @@ -489,32 +494,38 @@ class PDFEngine { virtual uint32_t GetLoadedByteSize() = 0; virtual bool ReadLoadedBytes(uint32_t length, void* buffer) = 0; + + // Requests for a thumbnail to be sent using a callback when the page is ready + // to be rendered. |send_callback| is run with the thumbnail data when ready. + virtual void RequestThumbnail(int page_index, + float device_pixel_ratio, + SendThumbnailCallback send_callback) = 0; }; // Interface for exports that wrap the PDF engine. class PDFEngineExports { public: struct RenderingSettings { - RenderingSettings(int dpi_x, - int dpi_y, - const pp::Rect& bounds, + RenderingSettings(const gfx::Size& dpi, + const gfx::Rect& bounds, bool fit_to_bounds, bool stretch_to_bounds, bool keep_aspect_ratio, bool center_in_bounds, bool autorotate, - bool use_color); + bool use_color, + bool render_for_printing); RenderingSettings(const RenderingSettings& that); - int dpi_x; - int dpi_y; - pp::Rect bounds; + gfx::Size dpi; + gfx::Rect bounds; bool fit_to_bounds; bool stretch_to_bounds; bool keep_aspect_ratio; bool center_in_bounds; bool autorotate; bool use_color; + bool render_for_printing; }; PDFEngineExports() {} @@ -564,7 +575,7 @@ class PDFEngineExports { virtual bool GetPDFDocInfo(base::span<const uint8_t> pdf_buffer, int* page_count, - double* max_page_width) = 0; + float* max_page_width) = 0; // Whether the PDF is Tagged (see 10.7 "Tagged PDF" in PDF Reference 1.7). // Returns true if it's a tagged (accessible) PDF, false if it's a valid @@ -579,10 +590,9 @@ class PDFEngineExports { int page_index) = 0; // See the definition of GetPDFPageSizeByIndex in pdf.cc for details. - virtual bool GetPDFPageSizeByIndex(base::span<const uint8_t> pdf_buffer, - int page_number, - double* width, - double* height) = 0; + virtual base::Optional<gfx::SizeF> GetPDFPageSizeByIndex( + base::span<const uint8_t> pdf_buffer, + int page_number) = 0; }; } // namespace chrome_pdf diff --git a/chromium/pdf/pdf_init.cc b/chromium/pdf/pdf_init.cc index fdc1be3c81c..2d8eab22d56 100644 --- a/chromium/pdf/pdf_init.cc +++ b/chromium/pdf/pdf_init.cc @@ -8,16 +8,16 @@ namespace chrome_pdf { namespace { -bool g_sdk_initialized_via_pepper = false; +bool g_sdk_initialized_via_plugin = false; } // namespace -bool IsSDKInitializedViaPepper() { - return g_sdk_initialized_via_pepper; +bool IsSDKInitializedViaPlugin() { + return g_sdk_initialized_via_plugin; } -void SetIsSDKInitializedViaPepper(bool initialized_via_pepper) { - g_sdk_initialized_via_pepper = initialized_via_pepper; +void SetIsSDKInitializedViaPlugin(bool initialized_via_plugin) { + g_sdk_initialized_via_plugin = initialized_via_plugin; } } // namespace chrome_pdf diff --git a/chromium/pdf/pdf_init.h b/chromium/pdf/pdf_init.h index 652ed9268e4..10a63fff0b3 100644 --- a/chromium/pdf/pdf_init.h +++ b/chromium/pdf/pdf_init.h @@ -7,8 +7,8 @@ namespace chrome_pdf { -bool IsSDKInitializedViaPepper(); -void SetIsSDKInitializedViaPepper(bool initialized_via_pepper); +bool IsSDKInitializedViaPlugin(); +void SetIsSDKInitializedViaPlugin(bool initialized_via_plugin); } // namespace chrome_pdf diff --git a/chromium/pdf/pdf_ppapi.cc b/chromium/pdf/pdf_ppapi.cc index 718fc21ce70..1ac23b1f53d 100644 --- a/chromium/pdf/pdf_ppapi.cc +++ b/chromium/pdf/pdf_ppapi.cc @@ -31,9 +31,9 @@ class PDFModule : public pp::Module { PDFModule::PDFModule() = default; PDFModule::~PDFModule() { - if (IsSDKInitializedViaPepper()) { + if (IsSDKInitializedViaPlugin()) { ShutdownSDK(); - SetIsSDKInitializedViaPepper(false); + SetIsSDKInitializedViaPlugin(false); } } @@ -42,7 +42,7 @@ bool PDFModule::Init() { } pp::Instance* PDFModule::CreateInstance(PP_Instance instance) { - if (!IsSDKInitializedViaPepper()) { + if (!IsSDKInitializedViaPlugin()) { v8::StartupData snapshot; pp::PDF::GetV8ExternalSnapshotData(pp::InstanceHandle(instance), &snapshot.data, &snapshot.raw_size); @@ -51,7 +51,7 @@ pp::Instance* PDFModule::CreateInstance(PP_Instance instance) { } InitializeSDK(/*enable_v8=*/true); - SetIsSDKInitializedViaPepper(true); + SetIsSDKInitializedViaPlugin(true); } return new OutOfProcessInstance(instance); diff --git a/chromium/pdf/pdf_view_plugin_base.cc b/chromium/pdf/pdf_view_plugin_base.cc index 863c07459b1..046d81716e0 100644 --- a/chromium/pdf/pdf_view_plugin_base.cc +++ b/chromium/pdf/pdf_view_plugin_base.cc @@ -5,8 +5,14 @@ #include "pdf/pdf_view_plugin_base.h" #include <memory> +#include <string> +#include <utility> +#include "base/bind.h" +#include "base/callback.h" +#include "base/memory/weak_ptr.h" #include "pdf/pdfium/pdfium_engine.h" +#include "pdf/ppapi_migration/url_loader.h" namespace chrome_pdf { @@ -14,12 +20,28 @@ PdfViewPluginBase::PdfViewPluginBase() = default; PdfViewPluginBase::~PdfViewPluginBase() = default; -void PdfViewPluginBase::InitializeEngine(bool enable_javascript) { - engine_ = std::make_unique<PDFiumEngine>(this, enable_javascript); +void PdfViewPluginBase::InitializeEngine( + PDFiumFormFiller::ScriptOption script_option) { + engine_ = std::make_unique<PDFiumEngine>(this, script_option); } void PdfViewPluginBase::DestroyEngine() { engine_.reset(); } +void PdfViewPluginBase::LoadUrl(const std::string& url, bool is_print_preview) { + UrlRequest request; + request.url = url; + request.method = "GET"; + request.ignore_redirects = true; + + std::unique_ptr<UrlLoader> loader = CreateUrlLoaderInternal(); + UrlLoader* raw_loader = loader.get(); + raw_loader->Open( + request, + base::BindOnce(is_print_preview ? &PdfViewPluginBase::DidOpenPreview + : &PdfViewPluginBase::DidOpen, + GetWeakPtr(), std::move(loader))); +} + } // namespace chrome_pdf diff --git a/chromium/pdf/pdf_view_plugin_base.h b/chromium/pdf/pdf_view_plugin_base.h index c1f2f647733..566ca4f471e 100644 --- a/chromium/pdf/pdf_view_plugin_base.h +++ b/chromium/pdf/pdf_view_plugin_base.h @@ -7,11 +7,18 @@ #include "pdf/pdf_engine.h" +#include <stdint.h> + #include <memory> +#include <string> + +#include "base/memory/weak_ptr.h" +#include "pdf/pdfium/pdfium_form_filler.h" namespace chrome_pdf { class PDFiumEngine; +class UrlLoader; // Common base to share code between the two plugin implementations, // `OutOfProcessInstance` (Pepper) and `PdfViewWebPlugin` (Blink). @@ -24,11 +31,8 @@ class PdfViewPluginBase : public PDFEngine::Client { PdfViewPluginBase(); ~PdfViewPluginBase() override; - // Initializes the main `PDFiumEngine`. If `enable_javascript` is true, the - // engine will support executing JavaScript. - // - // Any existing engine will be replaced. - void InitializeEngine(bool enable_javascript); + // Initializes the main `PDFiumEngine`. Any existing engine will be replaced. + void InitializeEngine(PDFiumFormFiller::ScriptOption script_option); // Destroys the main `PDFiumEngine`. Subclasses should call this method in // their destructor to ensure the engine is destroyed first. @@ -36,6 +40,24 @@ class PdfViewPluginBase : public PDFEngine::Client { PDFiumEngine* engine() { return engine_.get(); } + // 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); + + // Gets a weak pointer with a lifetime matching the derived class. + virtual base::WeakPtr<PdfViewPluginBase> GetWeakPtr() = 0; + + // Creates a URL loader and allows it to access all urls, i.e. not just the + // 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; + + // Handles `LoadUrl()` result for print preview. + virtual void DidOpenPreview(std::unique_ptr<UrlLoader> loader, + int32_t result) = 0; + private: std::unique_ptr<PDFiumEngine> engine_; }; diff --git a/chromium/pdf/pdf_view_web_plugin.cc b/chromium/pdf/pdf_view_web_plugin.cc index 8c7cdda8439..3d8caee239a 100644 --- a/chromium/pdf/pdf_view_web_plugin.cc +++ b/chromium/pdf/pdf_view_web_plugin.cc @@ -6,42 +6,125 @@ #include <stddef.h> +#include <memory> #include <string> +#include <utility> #include <vector> #include "base/check_op.h" +#include "base/memory/ptr_util.h" +#include "base/notreached.h" +#include "base/thread_annotations.h" +#include "base/threading/thread_checker.h" #include "cc/paint/paint_canvas.h" +#include "net/cookies/site_for_cookies.h" #include "pdf/pdf_engine.h" -#include "ppapi/cpp/url_loader.h" +#include "pdf/pdf_init.h" +#include "pdf/pdfium/pdfium_engine.h" +#include "pdf/ppapi_migration/url_loader.h" +#include "ppapi/c/pp_errors.h" #include "third_party/blink/public/common/input/web_coalesced_input_event.h" #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_rect.h" +#include "third_party/blink/public/platform/web_string.h" +#include "third_party/blink/public/platform/web_url.h" #include "third_party/blink/public/platform/web_url_error.h" +#include "third_party/blink/public/platform/web_url_request.h" #include "third_party/blink/public/platform/web_url_response.h" +#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_local_frame.h" #include "third_party/blink/public/web/web_plugin_container.h" #include "third_party/blink/public/web/web_plugin_params.h" #include "ui/base/cursor/cursor.h" namespace chrome_pdf { -PdfViewWebPlugin::PdfViewWebPlugin(const blink::WebPluginParams& params) {} +namespace { -PdfViewWebPlugin::~PdfViewWebPlugin() { - // Explicitly destroy the PDFEngine during destruction as it may call back - // into this object. - DestroyEngine(); -} +// Initialization performed per renderer process. Initialization may be +// triggered from multiple plugin instances, but should only execute once. +// +// TODO(crbug.com/1123621): We may be able to simplify this once we've figured +// out exactly which processes need to initialize and shutdown PDFium. +class PerProcessInitializer final { + public: + static PerProcessInitializer& GetInstance() { + static PerProcessInitializer instance; + return instance; + } + + void Acquire() { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + + DCHECK_GE(init_count_, 0); + if (init_count_++ > 0) + return; + + DCHECK(!IsSDKInitializedViaPlugin()); + // TODO(crbug.com/1111024): Support JavaScript. + InitializeSDK(/*enable_v8=*/false); + SetIsSDKInitializedViaPlugin(true); + } + + void Release() { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + + DCHECK_GT(init_count_, 0); + if (--init_count_ > 0) + return; + + DCHECK(IsSDKInitializedViaPlugin()); + ShutdownSDK(); + SetIsSDKInitializedViaPlugin(false); + } + + private: + int init_count_ GUARDED_BY_CONTEXT(thread_checker_) = 0; + + // TODO(crbug.com/1123731): Assuming PDFium is thread-hostile for now, and + // must use one thread exclusively. + THREAD_CHECKER(thread_checker_); +}; + +} // namespace +PdfViewWebPlugin::PdfViewWebPlugin(const blink::WebPluginParams& params) + : initial_params_(params) {} + +PdfViewWebPlugin::~PdfViewWebPlugin() = default; + +// Modeled on `OutOfProcessInstance::Init()`. bool PdfViewWebPlugin::Initialize(blink::WebPluginContainer* container) { DCHECK_EQ(container->Plugin(), this); container_ = container; - InitializeEngine(/*enable_javascript=*/false); + + std::string stream_url; + for (size_t i = 0; i < initial_params_.attribute_names.size(); ++i) { + if (initial_params_.attribute_names[i] == "stream-url") + stream_url = initial_params_.attribute_values[i].Utf8(); + } + + // Contents of `initial_params_` no longer needed. + initial_params_ = {}; + + PerProcessInitializer::GetInstance().Acquire(); + InitializeEngine(PDFiumFormFiller::ScriptOption::kNoJavaScript); + LoadUrl(stream_url, /*is_print_preview=*/false); return true; } void PdfViewWebPlugin::Destroy() { + if (container_) { + // Explicitly destroy the PDFEngine during destruction as it may call back + // into this object. + DestroyEngine(); + PerProcessInitializer::GetInstance().Release(); + } + container_ = nullptr; delete this; } @@ -83,7 +166,7 @@ void PdfViewWebPlugin::DidFailLoading(const blink::WebURLError& error) {} void PdfViewWebPlugin::ProposeDocumentLayout(const DocumentLayout& layout) {} -void PdfViewWebPlugin::Invalidate(const pp::Rect& rect) {} +void PdfViewWebPlugin::Invalidate(const gfx::Rect& rect) {} void PdfViewWebPlugin::DidScroll(const gfx::Vector2d& offset) {} @@ -106,8 +189,8 @@ void PdfViewWebPlugin::NavigateToDestination(int page, void PdfViewWebPlugin::UpdateCursor(PP_CursorType_Dev cursor) {} -void PdfViewWebPlugin::UpdateTickMarks(const std::vector<pp::Rect>& tickmarks) { -} +void PdfViewWebPlugin::UpdateTickMarks( + const std::vector<gfx::Rect>& tickmarks) {} void PdfViewWebPlugin::NotifyNumberOfFindResultsChanged(int total, bool final_result) {} @@ -149,8 +232,8 @@ void PdfViewWebPlugin::SubmitForm(const std::string& url, const void* data, int length) {} -pp::URLLoader PdfViewWebPlugin::CreateURLLoader() { - return pp::URLLoader(); +std::unique_ptr<UrlLoader> PdfViewWebPlugin::CreateUrlLoader() { + return nullptr; } std::vector<PDFEngine::Client::SearchStringResult> @@ -161,9 +244,13 @@ PdfViewWebPlugin::SearchString(const base::char16* string, } void PdfViewWebPlugin::DocumentLoadComplete( - const PDFEngine::DocumentFeatures& document_features) {} + const PDFEngine::DocumentFeatures& document_features) { + NOTIMPLEMENTED(); +} -void PdfViewWebPlugin::DocumentLoadFailed() {} +void PdfViewWebPlugin::DocumentLoadFailed() { + NOTIMPLEMENTED(); +} pp::Instance* PdfViewWebPlugin::GetPluginInstance() { return nullptr; @@ -187,8 +274,8 @@ uint32_t PdfViewWebPlugin::GetBackgroundColor() { void PdfViewWebPlugin::IsSelectingChanged(bool is_selecting) {} -void PdfViewWebPlugin::SelectionChanged(const pp::Rect& left, - const pp::Rect& right) {} +void PdfViewWebPlugin::SelectionChanged(const gfx::Rect& left, + const gfx::Rect& right) {} void PdfViewWebPlugin::EnteredEditMode() {} @@ -198,4 +285,63 @@ float PdfViewWebPlugin::GetToolbarHeightInScreenCoords() { void PdfViewWebPlugin::DocumentFocusChanged(bool document_has_focus) {} +bool PdfViewWebPlugin::IsValid() const { + return container_ && container_->GetDocument().GetFrame(); +} + +blink::WebURL PdfViewWebPlugin::CompleteURL( + const blink::WebString& partial_url) const { + DCHECK(IsValid()); + return container_->GetDocument().CompleteURL(partial_url); +} + +net::SiteForCookies PdfViewWebPlugin::SiteForCookies() const { + DCHECK(IsValid()); + return container_->GetDocument().SiteForCookies(); +} + +void PdfViewWebPlugin::SetReferrerForRequest( + blink::WebURLRequest& request, + const blink::WebURL& referrer_url) { + DCHECK(IsValid()); + container_->GetDocument().GetFrame()->SetReferrerForRequest(request, + referrer_url); +} + +std::unique_ptr<blink::WebAssociatedURLLoader> +PdfViewWebPlugin::CreateAssociatedURLLoader( + const blink::WebAssociatedURLLoaderOptions& options) { + // TODO(crbug.com/1127146): blink::WebLocalFrame::CreateAssociatedURLLoader() + // really should return a std::unique_ptr instead. + DCHECK(IsValid()); + return base::WrapUnique( + container_->GetDocument().GetFrame()->CreateAssociatedURLLoader(options)); +} + +base::WeakPtr<PdfViewPluginBase> PdfViewWebPlugin::GetWeakPtr() { + return weak_factory_.GetWeakPtr(); +} + +std::unique_ptr<UrlLoader> PdfViewWebPlugin::CreateUrlLoaderInternal() { + auto loader = std::make_unique<BlinkUrlLoader>(weak_factory_.GetWeakPtr()); + loader->GrantUniversalAccess(); + return loader; +} + +// Modeled on `OutOfProcessInstance::DidOpen()`. +void PdfViewWebPlugin::DidOpen(std::unique_ptr<UrlLoader> loader, + int32_t result) { + if (result == PP_OK) { + if (!engine()->HandleDocumentLoad(std::move(loader))) + DocumentLoadFailed(); + } else { + NOTIMPLEMENTED(); + } +} + +void PdfViewWebPlugin::DidOpenPreview(std::unique_ptr<UrlLoader> loader, + int32_t result) { + NOTIMPLEMENTED(); +} + } // namespace chrome_pdf diff --git a/chromium/pdf/pdf_view_web_plugin.h b/chromium/pdf/pdf_view_web_plugin.h index da351e4435d..e396dad05c0 100644 --- a/chromium/pdf/pdf_view_web_plugin.h +++ b/chromium/pdf/pdf_view_web_plugin.h @@ -5,19 +5,22 @@ #ifndef PDF_PDF_VIEW_WEB_PLUGIN_H_ #define PDF_PDF_VIEW_WEB_PLUGIN_H_ +#include "base/memory/weak_ptr.h" #include "pdf/pdf_view_plugin_base.h" +#include "pdf/ppapi_migration/url_loader.h" #include "third_party/blink/public/web/web_plugin.h" +#include "third_party/blink/public/web/web_plugin_params.h" namespace blink { class WebPluginContainer; -struct WebPluginParams; } // namespace blink namespace chrome_pdf { // Skeleton for a `blink::WebPlugin` to replace `OutOfProcessInstance`. class PdfViewWebPlugin final : public PdfViewPluginBase, - public blink::WebPlugin { + public blink::WebPlugin, + public BlinkUrlLoader::Client { public: explicit PdfViewWebPlugin(const blink::WebPluginParams& params); PdfViewWebPlugin(const PdfViewWebPlugin& other) = delete; @@ -45,7 +48,7 @@ class PdfViewWebPlugin final : public PdfViewPluginBase, // PdfViewPluginBase: void ProposeDocumentLayout(const DocumentLayout& layout) override; - void Invalidate(const pp::Rect& rect) override; + void Invalidate(const gfx::Rect& rect) override; void DidScroll(const gfx::Vector2d& offset) override; void ScrollToX(int x_in_screen_coords) override; void ScrollToY(int y_in_screen_coords, bool compensate_for_toolbar) override; @@ -58,7 +61,7 @@ class PdfViewWebPlugin final : public PdfViewPluginBase, const float* y, const float* zoom) override; void UpdateCursor(PP_CursorType_Dev cursor) override; - void UpdateTickMarks(const std::vector<pp::Rect>& tickmarks) 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 NotifyTouchSelectionOccurred() override; @@ -79,7 +82,7 @@ class PdfViewWebPlugin final : public PdfViewPluginBase, void SubmitForm(const std::string& url, const void* data, int length) override; - pp::URLLoader CreateURLLoader() override; + std::unique_ptr<UrlLoader> CreateUrlLoader() override; std::vector<SearchStringResult> SearchString(const base::char16* string, const base::char16* term, bool case_sensitive) override; @@ -93,16 +96,36 @@ class PdfViewWebPlugin final : public PdfViewPluginBase, bool IsPrintPreview() override; uint32_t GetBackgroundColor() override; void IsSelectingChanged(bool is_selecting) override; - void SelectionChanged(const pp::Rect& left, const pp::Rect& right) override; + void SelectionChanged(const gfx::Rect& left, const gfx::Rect& right) override; void EnteredEditMode() override; float GetToolbarHeightInScreenCoords() override; void DocumentFocusChanged(bool document_has_focus) override; + // BlinkUrlLoader::Client: + bool IsValid() const override; + blink::WebURL CompleteURL(const blink::WebString& partial_url) const override; + net::SiteForCookies SiteForCookies() const override; + void SetReferrerForRequest(blink::WebURLRequest& request, + const blink::WebURL& referrer_url) override; + std::unique_ptr<blink::WebAssociatedURLLoader> CreateAssociatedURLLoader( + const blink::WebAssociatedURLLoaderOptions& options) override; + + 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 DidOpenPreview(std::unique_ptr<UrlLoader> loader, + int32_t result) override; + private: // Call `Destroy()` instead. ~PdfViewWebPlugin() override; + blink::WebPluginParams initial_params_; blink::WebPluginContainer* container_ = nullptr; + + base::WeakPtrFactory<PdfViewWebPlugin> weak_factory_{this}; }; } // namespace chrome_pdf diff --git a/chromium/pdf/pdfium/DEPS b/chromium/pdf/pdfium/DEPS index 2a0dae302f3..365499c900f 100644 --- a/chromium/pdf/pdfium/DEPS +++ b/chromium/pdf/pdfium/DEPS @@ -1,4 +1,6 @@ include_rules = [ + "+cc/test/pixel_comparator.h", + "+cc/test/pixel_test_utils.h", "+gin/array_buffer.h", "+gin/public", "+gin/v8_initializer.h", diff --git a/chromium/pdf/pdfium/accessibility_unittest.cc b/chromium/pdf/pdfium/accessibility_unittest.cc index 8ded6bfb7cd..00e396337c4 100644 --- a/chromium/pdf/pdfium/accessibility_unittest.cc +++ b/chromium/pdf/pdfium/accessibility_unittest.cc @@ -4,12 +4,15 @@ #include "pdf/accessibility.h" +#include <string> + #include "pdf/pdfium/pdfium_engine.h" #include "pdf/pdfium/pdfium_test_base.h" +#include "pdf/ppapi_migration/geometry_conversions.h" #include "pdf/test/test_client.h" -#include "pdf/test/test_utils.h" #include "ppapi/c/private/ppp_pdf.h" #include "testing/gtest/include/gtest/gtest.h" +#include "ui/gfx/geometry/rect_f.h" #include "ui/gfx/geometry/vector2d.h" namespace chrome_pdf { @@ -111,12 +114,16 @@ TEST_F(AccessibilityTest, GetAccessibilityPage) { } TEST_F(AccessibilityTest, GetAccessibilityImageInfo) { - static const pp::PDF::PrivateAccessibilityImageInfo kExpectedImageInfo[] = { - {"Image 1", 0, {{380, 78}, {67, 68}}}, - {"Image 2", 0, {{380, 385}, {27, 28}}}, - {"Image 3", 0, {{380, 678}, {1, 1}}}}; + // Clone of pp::PDF::PrivateAccessibilityImageInfo. + static const struct { + std::string alt_text; + uint32_t text_run_index; + gfx::RectF bounds; + } kExpectedImageInfo[] = {{"Image 1", 0, {380, 78, 67, 68}}, + {"Image 2", 0, {380, 385, 27, 28}}, + {"Image 3", 0, {380, 678, 1, 1}}}; - static const pp::Rect kExpectedPageRect = {{5, 3}, {816, 1056}}; + static constexpr gfx::Rect kExpectedPageRect(5, 3, 816, 1056); TestClient client; std::unique_ptr<PDFiumEngine> engine = @@ -131,14 +138,15 @@ TEST_F(AccessibilityTest, GetAccessibilityImageInfo) { ASSERT_TRUE(GetAccessibilityInfo(engine.get(), 0, &page_info, &text_runs, &chars, &page_objects)); EXPECT_EQ(0u, page_info.page_index); - CompareRect(kExpectedPageRect, page_info.bounds); + EXPECT_EQ(kExpectedPageRect, RectFromPPRect(page_info.bounds)); EXPECT_EQ(text_runs.size(), page_info.text_run_count); EXPECT_EQ(chars.size(), page_info.char_count); ASSERT_EQ(page_objects.images.size(), base::size(kExpectedImageInfo)); for (size_t i = 0; i < page_objects.images.size(); ++i) { EXPECT_EQ(page_objects.images[i].alt_text, kExpectedImageInfo[i].alt_text); - CompareRect(kExpectedImageInfo[i].bounds, page_objects.images[i].bounds); + EXPECT_EQ(kExpectedImageInfo[i].bounds, + RectFFromPPFloatRect(page_objects.images[i].bounds)); EXPECT_EQ(page_objects.images[i].text_run_index, kExpectedImageInfo[i].text_run_index); } @@ -157,7 +165,7 @@ TEST_F(AccessibilityTest, GetUnderlyingTextRangeForRect) { int start_index = -1; int char_count = 0; EXPECT_TRUE(page.GetUnderlyingTextRangeForRect( - pp::FloatRect(20.0f, 50.0f, 26.0f, 8.0f), &start_index, &char_count)); + gfx::RectF(20.0f, 50.0f, 26.0f, 8.0f), &start_index, &char_count)); EXPECT_EQ(start_index, 0); EXPECT_EQ(char_count, 5); @@ -167,7 +175,7 @@ TEST_F(AccessibilityTest, GetUnderlyingTextRangeForRect) { start_index = -1; char_count = 0; EXPECT_TRUE(page.GetUnderlyingTextRangeForRect( - pp::FloatRect(20.0f, 0.0f, 26.0f, 58.0f), &start_index, &char_count)); + gfx::RectF(20.0f, 0.0f, 26.0f, 58.0f), &start_index, &char_count)); EXPECT_EQ(start_index, 0); EXPECT_EQ(char_count, 5); @@ -176,7 +184,7 @@ TEST_F(AccessibilityTest, GetUnderlyingTextRangeForRect) { start_index = -9; char_count = -10; EXPECT_FALSE(page.GetUnderlyingTextRangeForRect( - pp::FloatRect(10.0f, 10.0f, 0.0f, 0.0f), &start_index, &char_count)); + gfx::RectF(10.0f, 10.0f, 0.0f, 0.0f), &start_index, &char_count)); EXPECT_EQ(start_index, -9); EXPECT_EQ(char_count, -10); } @@ -444,17 +452,23 @@ TEST_F(AccessibilityTest, TestInternalLinkClickActionHandling) { } TEST_F(AccessibilityTest, GetAccessibilityLinkInfo) { - static pp::PDF::PrivateAccessibilityLinkInfo expected_link_info[] = { - {"http://yahoo.com", 0, 1, 1, {{75, 191}, {110, 16}}}, - {"http://bing.com", 1, 4, 1, {{131, 121}, {138, 20}}}, - {"http://google.com", 2, 7, 1, {{82, 67}, {161, 21}}}}; + // Clone of pp::PDF::PrivateAccessibilityLinkInfo. + struct { + std::string url; + uint32_t index_in_page; + uint32_t text_run_index; + uint32_t text_run_count; + gfx::RectF bounds; + } expected_link_info[] = {{"http://yahoo.com", 0, 1, 1, {75, 191, 110, 16}}, + {"http://bing.com", 1, 4, 1, {131, 121, 138, 20}}, + {"http://google.com", 2, 7, 1, {82, 67, 161, 21}}}; if (IsRunningOnChromeOS()) { - expected_link_info[0].bounds = {{75, 192}, {110, 15}}; - expected_link_info[1].bounds = {{131, 120}, {138, 22}}; + expected_link_info[0].bounds = {75, 192, 110, 15}; + expected_link_info[1].bounds = {131, 120, 138, 22}; } - static const pp::Rect kExpectedPageRect = {{5, 3}, {533, 266}}; + static constexpr gfx::Rect kExpectedPageRect(5, 3, 533, 266); TestClient client; std::unique_ptr<PDFiumEngine> engine = @@ -469,7 +483,7 @@ TEST_F(AccessibilityTest, GetAccessibilityLinkInfo) { ASSERT_TRUE(GetAccessibilityInfo(engine.get(), 0, &page_info, &text_runs, &chars, &page_objects)); EXPECT_EQ(0u, page_info.page_index); - CompareRect(kExpectedPageRect, page_info.bounds); + EXPECT_EQ(kExpectedPageRect, RectFromPPRect(page_info.bounds)); EXPECT_EQ(text_runs.size(), page_info.text_run_count); EXPECT_EQ(chars.size(), page_info.char_count); ASSERT_EQ(page_objects.links.size(), base::size(expected_link_info)); @@ -479,7 +493,8 @@ TEST_F(AccessibilityTest, GetAccessibilityLinkInfo) { page_objects.links[i]; EXPECT_EQ(link_info.url, expected_link_info[i].url); EXPECT_EQ(link_info.index_in_page, expected_link_info[i].index_in_page); - CompareRect(expected_link_info[i].bounds, link_info.bounds); + EXPECT_EQ(expected_link_info[i].bounds, + RectFFromPPFloatRect(link_info.bounds)); EXPECT_EQ(link_info.text_run_index, expected_link_info[i].text_run_index); EXPECT_EQ(link_info.text_run_count, expected_link_info[i].text_run_count); } @@ -489,13 +504,20 @@ TEST_F(AccessibilityTest, GetAccessibilityHighlightInfo) { constexpr uint32_t kHighlightDefaultColor = MakeARGB(255, 255, 255, 0); constexpr uint32_t kHighlightRedColor = MakeARGB(102, 230, 0, 0); constexpr uint32_t kHighlightNoColor = MakeARGB(0, 0, 0, 0); - static const pp::PDF::PrivateAccessibilityHighlightInfo - kExpectedHighlightInfo[] = { - {"Text Note", 0, 0, 1, {{5, 196}, {49, 26}}, kHighlightDefaultColor}, - {"", 1, 2, 1, {{110, 196}, {77, 26}}, kHighlightRedColor}, - {"", 2, 3, 1, {{192, 196}, {13, 26}}, kHighlightNoColor}}; - - static const pp::Rect kExpectedPageRect = {{5, 3}, {533, 266}}; + // Clone of pp::PDF::PrivateAccessibilityHighlightInfo. + static const struct { + std::string note_text; + uint32_t index_in_page; + uint32_t text_run_index; + uint32_t text_run_count; + gfx::RectF bounds; + uint32_t color; + } kExpectedHighlightInfo[] = { + {"Text Note", 0, 0, 1, {5, 196, 49, 26}, kHighlightDefaultColor}, + {"", 1, 2, 1, {110, 196, 77, 26}, kHighlightRedColor}, + {"", 2, 3, 1, {192, 196, 13, 26}, kHighlightNoColor}}; + + static constexpr gfx::Rect kExpectedPageRect(5, 3, 533, 266); TestClient client; std::unique_ptr<PDFiumEngine> engine = @@ -510,7 +532,7 @@ TEST_F(AccessibilityTest, GetAccessibilityHighlightInfo) { ASSERT_TRUE(GetAccessibilityInfo(engine.get(), 0, &page_info, &text_runs, &chars, &page_objects)); EXPECT_EQ(0u, page_info.page_index); - CompareRect(kExpectedPageRect, page_info.bounds); + EXPECT_EQ(kExpectedPageRect, RectFromPPRect(page_info.bounds)); EXPECT_EQ(text_runs.size(), page_info.text_run_count); EXPECT_EQ(chars.size(), page_info.char_count); ASSERT_EQ(page_objects.highlights.size(), base::size(kExpectedHighlightInfo)); @@ -520,7 +542,8 @@ TEST_F(AccessibilityTest, GetAccessibilityHighlightInfo) { page_objects.highlights[i]; EXPECT_EQ(highlight_info.index_in_page, kExpectedHighlightInfo[i].index_in_page); - CompareRect(kExpectedHighlightInfo[i].bounds, highlight_info.bounds); + EXPECT_EQ(kExpectedHighlightInfo[i].bounds, + RectFFromPPFloatRect(highlight_info.bounds)); EXPECT_EQ(highlight_info.text_run_index, kExpectedHighlightInfo[i].text_run_index); EXPECT_EQ(highlight_info.text_run_count, @@ -531,28 +554,30 @@ TEST_F(AccessibilityTest, GetAccessibilityHighlightInfo) { } TEST_F(AccessibilityTest, GetAccessibilityTextFieldInfo) { - static const pp::PDF::PrivateAccessibilityTextFieldInfo - kExpectedTextFieldInfo[] = { - {"Text Box", "Text", false, false, false, 0, 5, {138, 230, 135, 41}}, - {"ReadOnly", - "Elephant", - true, - false, - false, - 1, - 5, - {138, 163, 135, 41}}, - {"Required", - "Required Field", - false, - true, - false, - 2, - 5, - {138, 303, 135, 34}}, - {"Password", "", false, false, true, 3, 5, {138, 356, 135, 35}}}; - - static const pp::Rect kExpectedPageRect = {{5, 3}, {400, 400}}; + // Clone of pp::PDF::PrivateAccessibilityTextFieldInfo. + static const struct { + std::string name; + std::string value; + bool is_read_only; + bool is_required; + bool is_password; + uint32_t index_in_page; + uint32_t text_run_index; + gfx::RectF bounds; + } kExpectedTextFieldInfo[] = { + {"Text Box", "Text", false, false, false, 0, 5, {138, 230, 135, 41}}, + {"ReadOnly", "Elephant", true, false, false, 1, 5, {138, 163, 135, 41}}, + {"Required", + "Required Field", + false, + true, + false, + 2, + 5, + {138, 303, 135, 34}}, + {"Password", "", false, false, true, 3, 5, {138, 356, 135, 35}}}; + + static constexpr gfx::Rect kExpectedPageRect(5, 3, 400, 400); TestClient client; std::unique_ptr<PDFiumEngine> engine = @@ -567,7 +592,7 @@ TEST_F(AccessibilityTest, GetAccessibilityTextFieldInfo) { ASSERT_TRUE(GetAccessibilityInfo(engine.get(), 0, &page_info, &text_runs, &chars, &page_objects)); EXPECT_EQ(0u, page_info.page_index); - CompareRect(kExpectedPageRect, page_info.bounds); + EXPECT_EQ(kExpectedPageRect, RectFromPPRect(page_info.bounds)); EXPECT_EQ(text_runs.size(), page_info.text_run_count); EXPECT_EQ(chars.size(), page_info.char_count); ASSERT_EQ(page_objects.form_fields.text_fields.size(), @@ -588,7 +613,8 @@ TEST_F(AccessibilityTest, GetAccessibilityTextFieldInfo) { text_field_info.index_in_page); EXPECT_EQ(kExpectedTextFieldInfo[i].text_run_index, text_field_info.text_run_index); - CompareRect(kExpectedTextFieldInfo[i].bounds, text_field_info.bounds); + EXPECT_EQ(kExpectedTextFieldInfo[i].bounds, + RectFFromPPFloatRect(text_field_info.bounds)); } } diff --git a/chromium/pdf/pdfium/pdfium_engine.cc b/chromium/pdf/pdfium/pdfium_engine.cc index d3b70a1f032..e3f6e6fa8eb 100644 --- a/chromium/pdf/pdfium/pdfium_engine.cc +++ b/chromium/pdf/pdfium/pdfium_engine.cc @@ -45,8 +45,8 @@ #include "pdf/ppapi_migration/bitmap.h" #include "pdf/ppapi_migration/geometry_conversions.h" #include "pdf/ppapi_migration/input_event_conversions.h" +#include "pdf/ppapi_migration/url_loader.h" #include "pdf/url_loader_wrapper_impl.h" -#include "ppapi/c/ppb_input_event.h" #include "ppapi/cpp/instance.h" #include "ppapi/cpp/private/pdf.h" #include "ppapi/cpp/var_dictionary.h" @@ -64,6 +64,7 @@ #include "ui/gfx/geometry/point.h" #include "ui/gfx/geometry/point_conversions.h" #include "ui/gfx/geometry/rect.h" +#include "ui/gfx/geometry/rect_f.h" #include "ui/gfx/geometry/size.h" #include "ui/gfx/geometry/vector2d.h" #include "v8/include/v8.h" @@ -222,6 +223,7 @@ bool FindMultipleClickBoundary(bool is_double_click, base::char16 cur) { return false; } +#if defined(PDF_ENABLE_V8) gin::IsolateHolder* g_isolate_holder = nullptr; bool IsV8Initialized() { @@ -247,6 +249,7 @@ void TearDownV8() { delete g_isolate_holder; g_isolate_holder = nullptr; } +#endif // defined(PDF_ENABLE_V8) // Returns true if the given |area| and |form_type| combination from // PDFiumEngine::GetCharIndex() indicates it is a form text area. @@ -396,7 +399,11 @@ void InitializeSDK(bool enable_v8) { FPDF_LIBRARY_CONFIG config; config.version = 3; config.m_pUserFontPaths = nullptr; + config.m_pIsolate = nullptr; + config.m_pPlatform = nullptr; + config.m_v8EmbedderSlot = gin::kEmbedderPDFium; +#if defined(PDF_ENABLE_V8) if (enable_v8) { SetUpV8(); config.m_pIsolate = v8::Isolate::GetCurrent(); @@ -404,11 +411,9 @@ void InitializeSDK(bool enable_v8) { // will manipulate the pointer value should gin::V8Platform someday have // multiple base classes. config.m_pPlatform = static_cast<v8::Platform*>(gin::V8Platform::Get()); - } else { - config.m_pIsolate = nullptr; - config.m_pPlatform = nullptr; } - config.m_v8EmbedderSlot = gin::kEmbedderPDFium; +#endif // defined(PDF_ENABLE_V8) + FPDF_InitLibraryWithConfig(&config); #if defined(OS_LINUX) || defined(OS_CHROMEOS) @@ -420,8 +425,10 @@ void InitializeSDK(bool enable_v8) { void ShutdownSDK() { FPDF_DestroyLibrary(); +#if defined(PDF_ENABLE_V8) if (IsV8Initialized()) TearDownV8(); +#endif // defined(PDF_ENABLE_V8) } PDFEngine::AccessibilityLinkInfo::AccessibilityLinkInfo() = default; @@ -452,14 +459,17 @@ PDFEngine::AccessibilityTextFieldInfo::AccessibilityTextFieldInfo( PDFEngine::AccessibilityTextFieldInfo::~AccessibilityTextFieldInfo() = default; -PDFiumEngine::PDFiumEngine(PDFEngine::Client* client, bool enable_javascript) +PDFiumEngine::PDFiumEngine(PDFEngine::Client* client, + PDFiumFormFiller::ScriptOption script_option) : client_(client), - form_filler_(this, enable_javascript), + form_filler_(this, script_option), mouse_down_state_(PDFiumPage::NONSELECTABLE_AREA, PDFiumPage::LinkTarget()), print_(this) { - if (enable_javascript) +#if defined(PDF_ENABLE_V8) + if (script_option != PDFiumFormFiller::ScriptOption::kNoJavaScript) DCHECK(IsV8Initialized()); +#endif // defined(PDF_ENABLE_V8) IFSDK_PAUSE::version = 1; IFSDK_PAUSE::user = nullptr; @@ -544,11 +554,11 @@ void PDFiumEngine::PrePaint() { paint.set_painted(false); } -void PDFiumEngine::Paint(const pp::Rect& rect, +void PDFiumEngine::Paint(const gfx::Rect& rect, SkBitmap& image_data, - std::vector<pp::Rect>& ready, - std::vector<pp::Rect>& pending) { - pp::Rect leftover = rect; + std::vector<gfx::Rect>& ready, + std::vector<gfx::Rect>& pending) { + gfx::Rect leftover = rect; for (size_t i = 0; i < visible_pages_.size(); ++i) { int index = visible_pages_[i]; // Convert the current page's rectangle to screen rectangle. We do this @@ -556,8 +566,9 @@ void PDFiumEngine::Paint(const pp::Rect& rect, // page coordinates) because then we'd have to convert back to screen // coordinates, and the rounding errors sometime leave pixels dirty or even // move the text up or down a pixel when zoomed. - pp::Rect page_rect_in_screen = GetPageScreenRect(index); - pp::Rect dirty_in_screen = page_rect_in_screen.Intersect(leftover); + gfx::Rect page_rect_in_screen = GetPageScreenRect(index); + gfx::Rect dirty_in_screen = + gfx::IntersectRects(page_rect_in_screen, leftover); if (dirty_in_screen.IsEmpty()) continue; @@ -569,13 +580,13 @@ void PDFiumEngine::Paint(const pp::Rect& rect, // rectangle. if (!layout_.options().two_up_view_enabled()) { if (i == 0) { - pp::Rect blank_space_in_screen = dirty_in_screen; + gfx::Rect blank_space_in_screen = dirty_in_screen; blank_space_in_screen.set_y(0); blank_space_in_screen.set_height(dirty_in_screen.y()); - leftover = leftover.Subtract(blank_space_in_screen); + leftover.Subtract(blank_space_in_screen); } - leftover = leftover.Subtract(dirty_in_screen); + leftover.Subtract(dirty_in_screen); } if (pages_[index]->available()) { @@ -630,14 +641,14 @@ void PDFiumEngine::PostPaint() { } } -bool PDFiumEngine::HandleDocumentLoad(const pp::URLLoader& loader) { +bool PDFiumEngine::HandleDocumentLoad(std::unique_ptr<UrlLoader> loader) { password_tries_remaining_ = kMaxPasswordTries; process_when_pending_request_complete_ = base::FeatureList::IsEnabled(features::kPdfIncrementalLoading); if (!doc_loader_set_for_testing_) { auto loader_wrapper = - std::make_unique<URLLoaderWrapperImpl>(GetPluginInstance(), loader); + std::make_unique<URLLoaderWrapperImpl>(std::move(loader)); loader_wrapper->SetResponseHeaders(headers_); doc_loader_ = std::make_unique<DocumentLoaderImpl>(this); @@ -656,8 +667,7 @@ pp::Instance* PDFiumEngine::GetPluginInstance() { } std::unique_ptr<URLLoaderWrapper> PDFiumEngine::CreateURLLoader() { - return std::make_unique<URLLoaderWrapperImpl>(GetPluginInstance(), - client_->CreateURLLoader()); + return std::make_unique<URLLoaderWrapperImpl>(client_->CreateUrlLoader()); } void PDFiumEngine::AppendPage(PDFEngine* engine, int index) { @@ -833,45 +843,44 @@ void PDFiumEngine::ContinueFind(int32_t result) { StartFind(current_find_text_, result != 0); } -bool PDFiumEngine::HandleEvent(const pp::InputEvent& event) { +bool PDFiumEngine::HandleEvent(const InputEvent& event) { DCHECK(!defer_page_unload_); defer_page_unload_ = true; bool rv = false; - switch (event.GetType()) { - case PP_INPUTEVENT_TYPE_MOUSEDOWN: - rv = OnMouseDown(GetMouseInputEvent(pp::MouseInputEvent(event))); + switch (event.GetEventType()) { + case InputEventType::kMouseDown: + rv = OnMouseDown(static_cast<const MouseInputEvent&>(event)); break; - case PP_INPUTEVENT_TYPE_MOUSEUP: - rv = OnMouseUp(GetMouseInputEvent(pp::MouseInputEvent(event))); + case InputEventType::kMouseUp: + rv = OnMouseUp(static_cast<const MouseInputEvent&>(event)); break; - case PP_INPUTEVENT_TYPE_MOUSEMOVE: - rv = OnMouseMove(GetMouseInputEvent(pp::MouseInputEvent(event))); + case InputEventType::kMouseMove: + rv = OnMouseMove(static_cast<const MouseInputEvent&>(event)); break; - case PP_INPUTEVENT_TYPE_MOUSEENTER: - OnMouseEnter(GetMouseInputEvent(pp::MouseInputEvent(event))); + case InputEventType::kMouseEnter: + OnMouseEnter(static_cast<const MouseInputEvent&>(event)); break; - case PP_INPUTEVENT_TYPE_KEYDOWN: - rv = OnKeyDown(GetKeyboardInputEvent(pp::KeyboardInputEvent(event))); + case InputEventType::kKeyDown: + rv = OnKeyDown(static_cast<const KeyboardInputEvent&>(event)); break; - case PP_INPUTEVENT_TYPE_KEYUP: - rv = OnKeyUp(GetKeyboardInputEvent(pp::KeyboardInputEvent(event))); + case InputEventType::kKeyUp: + rv = OnKeyUp(static_cast<const KeyboardInputEvent&>(event)); break; - case PP_INPUTEVENT_TYPE_CHAR: - rv = OnChar(GetKeyboardInputEvent(pp::KeyboardInputEvent(event))); + case InputEventType::kChar: + rv = OnChar(static_cast<const KeyboardInputEvent&>(event)); break; - case PP_INPUTEVENT_TYPE_TOUCHSTART: { + case InputEventType::kTouchStart: { KillTouchTimer(); - TouchInputEvent touch_event( - GetTouchInputEvent(pp::TouchInputEvent(event))); + const auto& touch_event = static_cast<const TouchInputEvent&>(event); if (touch_event.GetTouchCount() == 1) ScheduleTouchTimer(touch_event); break; } - case PP_INPUTEVENT_TYPE_TOUCHEND: + case InputEventType::kTouchEnd: KillTouchTimer(); break; - case PP_INPUTEVENT_TYPE_TOUCHMOVE: + case InputEventType::kTouchMove: // TODO(dsinclair): This should allow a little bit of movement (up to the // touch radii) to account for finger jiggle. KillTouchTimer(); @@ -1105,8 +1114,7 @@ PDFiumPage::Area PDFiumEngine::GetCharIndex(const gfx::Point& point, static_cast<int>((point.x() + position_.x()) / current_zoom_), static_cast<int>((point.y() + position_.y()) / current_zoom_)); for (int visible_page : visible_pages_) { - if (pages_[visible_page]->rect().Contains( - PPPointFromPoint(point_in_page))) { + if (pages_[visible_page]->rect().Contains(point_in_page)) { page = visible_page; break; } @@ -1322,10 +1330,10 @@ bool PDFiumEngine::OnRightMouseDown(const MouseInputEvent& event) { if (selection_.empty()) return false; - std::vector<pp::Rect> selection_rect_vector = GetAllScreenRectsUnion( - selection_, PointFromPPPoint(GetVisibleRect().point())); + std::vector<gfx::Rect> selection_rect_vector = + GetAllScreenRectsUnion(selection_, GetVisibleRect().origin()); for (const auto& rect : selection_rect_vector) { - if (rect.Contains(point.x(), point.y())) + if (rect.Contains(point)) return false; } SelectionChangeInvalidator selection_invalidator(this); @@ -1388,12 +1396,11 @@ bool PDFiumEngine::OnMouseUp(const MouseInputEvent& event) { // Open link on mouse up for same link for which mouse down happened earlier. if (mouse_down_state_.Matches(area, target)) { uint32_t modifiers = event.GetModifiers(); - bool middle_button = - !!(modifiers & PP_INPUTEVENT_MODIFIER_MIDDLEBUTTONDOWN); - bool alt_key = !!(modifiers & PP_INPUTEVENT_MODIFIER_ALTKEY); - bool ctrl_key = !!(modifiers & PP_INPUTEVENT_MODIFIER_CONTROLKEY); - bool meta_key = !!(modifiers & PP_INPUTEVENT_MODIFIER_METAKEY); - bool shift_key = !!(modifiers & PP_INPUTEVENT_MODIFIER_SHIFTKEY); + bool middle_button = !!(modifiers & kInputEventModifierMiddleButtonDown); + bool alt_key = !!(modifiers & kInputEventModifierAltKey); + bool ctrl_key = !!(modifiers & kInputEventModifierControlKey); + bool meta_key = !!(modifiers & kInputEventModifierMetaKey); + bool shift_key = !!(modifiers & kInputEventModifierShiftKey); WindowOpenDisposition disposition = ui::DispositionFromClick( middle_button, alt_key, ctrl_key, meta_key, shift_key); @@ -1530,7 +1537,7 @@ PP_CursorType_Dev PDFiumEngine::DetermineCursorType(PDFiumPage::Area area, } void PDFiumEngine::OnMouseEnter(const MouseInputEvent& event) { - if (event.GetModifiers() & PP_INPUTEVENT_MODIFIER_MIDDLEBUTTONDOWN) { + if (event.GetModifiers() & kInputEventModifierMiddleButtonDown) { if (!mouse_middle_button_down_) { mouse_middle_button_down_ = true; mouse_middle_button_last_position_ = event.GetPosition(); @@ -1637,7 +1644,7 @@ bool PDFiumEngine::OnKeyDown(const KeyboardInputEvent& event) { // Scroll focused annotation into view when context menu is invoked through // keyboard <Shift-F10>. if (event.GetKeyCode() == FWL_VKEY_F10 && - (event.GetModifiers() & PP_INPUTEVENT_MODIFIER_SHIFTKEY)) { + (event.GetModifiers() & kInputEventModifierShiftKey)) { DCHECK(!rv); ScrollFocusedAnnotationIntoView(); } @@ -1980,8 +1987,8 @@ bool PDFiumEngine::SelectFindResult(bool forward) { selection_.push_back(find_results_[current_find_index_.value()]); // If the result is not in view, scroll to it. - pp::Rect bounding_rect; - pp::Rect visible_rect = GetVisibleRect(); + gfx::Rect bounding_rect; + gfx::Rect visible_rect = GetVisibleRect(); // TODO(crbug.com/1108574): Remove after fixing the issue. size_t find_results_size = find_results_.size(); @@ -1990,13 +1997,13 @@ bool PDFiumEngine::SelectFindResult(bool forward) { base::debug::Alias(¤t_find_index_value); // Use zoom of 1.0 since |visible_rect| is without zoom. - const std::vector<pp::Rect>& rects = + const std::vector<gfx::Rect>& rects = find_results_[current_find_index_.value()].GetScreenRects( gfx::Point(), 1.0, layout_.options().default_page_orientation()); for (const auto& rect : rects) - bounding_rect = bounding_rect.Union(rect); + bounding_rect.Union(rect); if (!visible_rect.Contains(bounding_rect)) { - gfx::Point center = PointFromPPPoint(bounding_rect.CenterPoint()); + gfx::Point center = bounding_rect.CenterPoint(); // Make the page centered. int new_y = CalculateCenterForZoom(center.y(), visible_rect.height(), current_zoom_); @@ -2033,24 +2040,24 @@ void PDFiumEngine::StopFind() { find_weak_factory_.InvalidateWeakPtrs(); } -std::vector<pp::Rect> PDFiumEngine::GetAllScreenRectsUnion( +std::vector<gfx::Rect> PDFiumEngine::GetAllScreenRectsUnion( const std::vector<PDFiumRange>& rect_range, const gfx::Point& point) const { - std::vector<pp::Rect> rect_vector; + std::vector<gfx::Rect> rect_vector; rect_vector.reserve(rect_range.size()); for (const auto& range : rect_range) { - pp::Rect result_rect; - const std::vector<pp::Rect>& rects = range.GetScreenRects( + gfx::Rect result_rect; + const std::vector<gfx::Rect>& rects = range.GetScreenRects( point, current_zoom_, layout_.options().default_page_orientation()); for (const auto& rect : rects) - result_rect = result_rect.Union(rect); + result_rect.Union(rect); rect_vector.push_back(result_rect); } return rect_vector; } void PDFiumEngine::UpdateTickMarks() { - std::vector<pp::Rect> tickmarks = + std::vector<gfx::Rect> tickmarks = GetAllScreenRectsUnion(find_results_, gfx::Point()); client_->UpdateTickMarks(tickmarks); } @@ -2092,7 +2099,7 @@ void PDFiumEngine::InvalidateAllPages() { StopFind(); DCHECK(document_loaded_); RefreshCurrentDocumentLayout(); - client_->Invalidate(pp::Rect(PPSizeFromSize(plugin_size_))); + client_->Invalidate(gfx::Rect(plugin_size_)); } std::string PDFiumEngine::GetSelectedText() { @@ -2167,7 +2174,7 @@ void PDFiumEngine::HandleAccessibilityAction( const PP_PdfAccessibilityActionData& action_data) { switch (action_data.action) { case PP_PdfAccessibilityAction::PP_PDF_SCROLL_TO_MAKE_VISIBLE: { - ScrollBasedOnScrollAlignment(action_data.target_rect, + ScrollBasedOnScrollAlignment(RectFromPPRect(action_data.target_rect), action_data.horizontal_scroll_alignment, action_data.vertical_scroll_alignment); break; @@ -2187,7 +2194,7 @@ void PDFiumEngine::HandleAccessibilityAction( break; } case PP_PdfAccessibilityAction::PP_PDF_SCROLL_TO_GLOBAL_POINT: { - ScrollToGlobalPoint(action_data.target_rect, + ScrollToGlobalPoint(RectFromPPRect(action_data.target_rect), PointFromPPPoint(action_data.target_point)); break; } @@ -2338,11 +2345,10 @@ pp::VarDictionary PDFiumEngine::TraverseBookmarks(FPDF_BOOKMARK bookmark, } void PDFiumEngine::ScrollBasedOnScrollAlignment( - const pp::Rect& scroll_rect, + const gfx::Rect& scroll_rect, const PP_PdfAccessibilityScrollAlignment& horizontal_scroll_alignment, const PP_PdfAccessibilityScrollAlignment& vertical_scroll_alignment) { - gfx::Vector2d scroll_offset = - PointFromPPPoint(GetScreenRect(scroll_rect).point()).OffsetFromOrigin(); + gfx::Vector2d scroll_offset = GetScreenRect(scroll_rect).OffsetFromOrigin(); switch (horizontal_scroll_alignment) { case PP_PdfAccessibilityScrollAlignment::PP_PDF_SCROLL_ALIGNMENT_RIGHT: scroll_offset.set_x(scroll_offset.x() - plugin_size_.width()); @@ -2394,10 +2400,9 @@ void PDFiumEngine::ScrollBasedOnScrollAlignment( client_->ScrollBy(scroll_offset); } -void PDFiumEngine::ScrollToGlobalPoint(const pp::Rect& target_rect, +void PDFiumEngine::ScrollToGlobalPoint(const gfx::Rect& target_rect, const gfx::Point& global_point) { - gfx::Point scroll_offset = - PointFromPPPoint(GetScreenRect(target_rect).point()); + gfx::Point scroll_offset = GetScreenRect(target_rect).origin(); client_->ScrollBy(scroll_offset - global_point); } @@ -2443,11 +2448,11 @@ int PDFiumEngine::GetMostVisiblePage() { return most_visible_page_; } -pp::Rect PDFiumEngine::GetPageBoundsRect(int index) { +gfx::Rect PDFiumEngine::GetPageBoundsRect(int index) { return pages_[index]->rect(); } -pp::Rect PDFiumEngine::GetPageContentsRect(int index) { +gfx::Rect PDFiumEngine::GetPageContentsRect(int index) { return GetScreenRect(pages_[index]->rect()); } @@ -2476,7 +2481,7 @@ int PDFiumEngine::GetCharCount(int page_index) { return pages_[page_index]->GetCharCount(); } -pp::FloatRect PDFiumEngine::GetCharBounds(int page_index, int char_index) { +gfx::RectF PDFiumEngine::GetCharBounds(int page_index, int char_index) { DCHECK(PageIndexInBounds(page_index)); return pages_[page_index]->GetCharBounds(char_index); } @@ -2834,10 +2839,11 @@ void PDFiumEngine::LoadForm() { ScopedUnsupportedFeature scoped_unsupported_feature(this); document_->InitializeForm(&form_filler_); } -#if defined(PDF_ENABLE_XFA) - FPDF_LoadXFA(doc()); -#endif + if (form_filler_.script_option() == + PDFiumFormFiller::ScriptOption::kJavaScriptAndXFA) { + FPDF_LoadXFA(doc()); + } FPDF_SetFormFieldHighlightColor(form(), FPDF_FORMFIELD_UNKNOWN, kFormHighlightColor); FPDF_SetFormFieldHighlightAlpha(form(), kFormHighlightAlpha); @@ -2868,7 +2874,7 @@ void PDFiumEngine::CalculateVisiblePages() { doc_loader_->ClearPendingRequests(); visible_pages_.clear(); - pp::Rect visible_rect(PPSizeFromSize(plugin_size_)); + gfx::Rect visible_rect(plugin_size_); for (int i = 0; i < static_cast<int>(pages_.size()); ++i) { // Check an entire PageScreenRect, since we might need to repaint side // borders and shadows even if the page itself is not visible. @@ -2895,8 +2901,8 @@ void PDFiumEngine::CalculateVisiblePages() { std::vector<draw_utils::IndexedPage> visible_pages_rects; visible_pages_rects.reserve(visible_pages_.size()); for (int visible_page_index : visible_pages_) { - visible_pages_rects.push_back( - {visible_page_index, pages_[visible_page_index]->rect()}); + visible_pages_rects.emplace_back(visible_page_index, + pages_[visible_page_index]->rect()); } int most_visible_page = @@ -2945,33 +2951,28 @@ gfx::Size PDFiumEngine::GetPageSize(int index) { gfx::Size PDFiumEngine::GetPageSizeForLayout( int index, const DocumentLayout::Options& layout_options) { - gfx::Size size; - double width_in_points = 0; - double height_in_points = 0; - int rv = FPDF_GetPageSizeByIndex(doc(), index, &width_in_points, - &height_in_points); - - if (rv) { - int width_in_pixels = static_cast<int>( - ConvertUnitDouble(width_in_points, kPointsPerInch, kPixelsPerInch)); - int height_in_pixels = static_cast<int>( - ConvertUnitDouble(height_in_points, kPointsPerInch, kPixelsPerInch)); - - switch (layout_options.default_page_orientation()) { - case PageOrientation::kOriginal: - case PageOrientation::kClockwise180: - // No axis swap needed. - break; - case PageOrientation::kClockwise90: - case PageOrientation::kClockwise270: - // Rotated 90 degrees: swap axes. - std::swap(width_in_pixels, height_in_pixels); - break; - } - - size = gfx::Size(width_in_pixels, height_in_pixels); + FS_SIZEF size_in_points; + if (!FPDF_GetPageSizeByIndexF(doc(), index, &size_in_points)) + return gfx::Size(); + + int width_in_pixels = static_cast<int>( + ConvertUnitDouble(size_in_points.width, kPointsPerInch, kPixelsPerInch)); + int height_in_pixels = static_cast<int>( + ConvertUnitDouble(size_in_points.height, kPointsPerInch, kPixelsPerInch)); + + switch (layout_options.default_page_orientation()) { + case PageOrientation::kOriginal: + case PageOrientation::kClockwise180: + // No axis swap needed. + break; + case PageOrientation::kClockwise90: + case PageOrientation::kClockwise270: + // Rotated 90 degrees: swap axes. + std::swap(width_in_pixels, height_in_pixels); + break; } - return size; + + return gfx::Size(width_in_pixels, height_in_pixels); } draw_utils::PageInsetSizes PDFiumEngine::GetInsetSizes( @@ -3003,13 +3004,13 @@ void PDFiumEngine::InsetPage(const DocumentLayout::Options& layout_options, size_t page_index, size_t num_of_pages, double multiplier, - pp::Rect* rect) const { + gfx::Rect& rect) const { draw_utils::PageInsetSizes inset_sizes = GetInsetSizes(layout_options, page_index, num_of_pages); - rect->Inset(static_cast<int>(ceil(inset_sizes.left * multiplier)), - static_cast<int>(ceil(inset_sizes.top * multiplier)), - static_cast<int>(ceil(inset_sizes.right * multiplier)), - static_cast<int>(ceil(inset_sizes.bottom * multiplier))); + rect.Inset(static_cast<int>(ceil(inset_sizes.left * multiplier)), + static_cast<int>(ceil(inset_sizes.top * multiplier)), + static_cast<int>(ceil(inset_sizes.right * multiplier)), + static_cast<int>(ceil(inset_sizes.bottom * multiplier))); } base::Optional<size_t> PDFiumEngine::GetAdjacentPageIndexForTwoUpView( @@ -3028,7 +3029,7 @@ base::Optional<size_t> PDFiumEngine::GetAdjacentPageIndexForTwoUpView( return adjacent_page_index; } -int PDFiumEngine::StartPaint(int page_index, const pp::Rect& dirty) { +int PDFiumEngine::StartPaint(int page_index, const gfx::Rect& dirty) { // For the first time we hit paint, do nothing and just record the paint for // the next callback. This keeps the UI responsive in case the user is doing // a lot of scrolling. @@ -3057,7 +3058,7 @@ bool PDFiumEngine::ContinuePaint(int progressive_index, SkBitmap& image_data) { int start_y; int size_x; int size_y; - pp::Rect dirty = progressive_paints_[progressive_index].rect(); + gfx::Rect dirty = progressive_paints_[progressive_index].rect(); GetPDFiumRect(page_index, dirty, &start_x, &start_y, &size_x, &size_y); ScopedFPDFBitmap new_bitmap = CreateBitmap(dirty, image_data); @@ -3078,8 +3079,7 @@ void PDFiumEngine::FinishPaint(int progressive_index, SkBitmap& image_data) { DCHECK_LT(static_cast<size_t>(progressive_index), progressive_paints_.size()); int page_index = progressive_paints_[progressive_index].page_index(); - const pp::Rect& dirty_in_screen = - progressive_paints_[progressive_index].rect(); + gfx::Rect dirty_in_screen = progressive_paints_[progressive_index].rect(); int start_x; int start_y; @@ -3119,21 +3119,20 @@ void PDFiumEngine::FillPageSides(int progressive_index) { DCHECK_LT(static_cast<size_t>(progressive_index), progressive_paints_.size()); int page_index = progressive_paints_[progressive_index].page_index(); - const pp::Rect& dirty_in_screen = - progressive_paints_[progressive_index].rect(); + gfx::Rect dirty_in_screen = progressive_paints_[progressive_index].rect(); FPDF_BITMAP bitmap = progressive_paints_[progressive_index].bitmap(); draw_utils::PageInsetSizes inset_sizes = GetInsetSizes(layout_.options(), page_index, pages_.size()); - pp::Rect page_rect = pages_[page_index]->rect(); + gfx::Rect page_rect = pages_[page_index]->rect(); const bool is_two_up_view = layout_.options().two_up_view_enabled(); if (page_rect.x() > 0 && (!is_two_up_view || page_index % 2 == 0)) { // If in two-up view, only need to draw the left empty space for left pages // since the gap between the left and right page will be drawn by the left // page. - pp::Rect left_in_screen = GetScreenRect(draw_utils::GetLeftFillRect( + gfx::Rect left_in_screen = GetScreenRect(draw_utils::GetLeftFillRect( page_rect, inset_sizes, DocumentLayout::kBottomSeparator)); - left_in_screen = left_in_screen.Intersect(dirty_in_screen); + left_in_screen.Intersect(dirty_in_screen); FPDFBitmap_FillRect(bitmap, left_in_screen.x() - dirty_in_screen.x(), left_in_screen.y() - dirty_in_screen.y(), @@ -3142,10 +3141,10 @@ void PDFiumEngine::FillPageSides(int progressive_index) { } if (page_rect.right() < layout_.size().width()) { - pp::Rect right_in_screen = GetScreenRect(draw_utils::GetRightFillRect( + gfx::Rect right_in_screen = GetScreenRect(draw_utils::GetRightFillRect( page_rect, inset_sizes, layout_.size().width(), DocumentLayout::kBottomSeparator)); - right_in_screen = right_in_screen.Intersect(dirty_in_screen); + right_in_screen.Intersect(dirty_in_screen); FPDFBitmap_FillRect(bitmap, right_in_screen.x() - dirty_in_screen.x(), right_in_screen.y() - dirty_in_screen.y(), @@ -3153,9 +3152,9 @@ void PDFiumEngine::FillPageSides(int progressive_index) { client_->GetBackgroundColor()); } - pp::Rect bottom_in_screen; + gfx::Rect bottom_in_screen; if (is_two_up_view) { - pp::Rect page_in_screen = GetScreenRect(page_rect); + gfx::Rect page_in_screen = GetScreenRect(page_rect); bottom_in_screen = draw_utils::GetBottomGapBetweenRects( page_in_screen.bottom(), dirty_in_screen); @@ -3164,11 +3163,11 @@ void PDFiumEngine::FillPageSides(int progressive_index) { &bottom_in_screen); } - bottom_in_screen = bottom_in_screen.Intersect(dirty_in_screen); + bottom_in_screen.Intersect(dirty_in_screen); } else { bottom_in_screen = GetScreenRect(draw_utils::GetBottomFillRect( page_rect, inset_sizes, DocumentLayout::kBottomSeparator)); - bottom_in_screen = bottom_in_screen.Intersect(dirty_in_screen); + bottom_in_screen.Intersect(dirty_in_screen); } FPDFBitmap_FillRect(bitmap, bottom_in_screen.x() - dirty_in_screen.x(), @@ -3183,12 +3182,11 @@ void PDFiumEngine::PaintPageShadow(int progressive_index, DCHECK_LT(static_cast<size_t>(progressive_index), progressive_paints_.size()); int page_index = progressive_paints_[progressive_index].page_index(); - const pp::Rect& dirty_in_screen = - progressive_paints_[progressive_index].rect(); - pp::Rect page_rect = pages_[page_index]->rect(); - pp::Rect shadow_rect(page_rect); + gfx::Rect dirty_in_screen = progressive_paints_[progressive_index].rect(); + gfx::Rect page_rect = pages_[page_index]->rect(); + gfx::Rect shadow_rect(page_rect); InsetPage(layout_.options(), page_index, pages_.size(), /*multiplier=*/-1, - &shadow_rect); + shadow_rect); // Due to the rounding errors of the GetScreenRect it is possible to get // different size shadows on the left and right sides even they are defined @@ -3197,7 +3195,7 @@ void PDFiumEngine::PaintPageShadow(int progressive_index, shadow_rect = GetScreenRect(shadow_rect); page_rect = shadow_rect; InsetPage(layout_.options(), page_index, pages_.size(), - /*multiplier=*/current_zoom_, &page_rect); + /*multiplier=*/current_zoom_, page_rect); DrawPageShadow(page_rect, shadow_rect, dirty_in_screen, image_data); } @@ -3208,49 +3206,46 @@ void PDFiumEngine::DrawSelections(int progressive_index, DCHECK_LT(static_cast<size_t>(progressive_index), progressive_paints_.size()); int page_index = progressive_paints_[progressive_index].page_index(); - const pp::Rect& dirty_in_screen = - progressive_paints_[progressive_index].rect(); + gfx::Rect dirty_in_screen = progressive_paints_[progressive_index].rect(); void* region = nullptr; int stride; - GetRegion(PointFromPPPoint(dirty_in_screen.point()), image_data, region, - stride); + GetRegion(dirty_in_screen.origin(), image_data, region, stride); - std::vector<pp::Rect> highlighted_rects; - pp::Rect visible_rect = GetVisibleRect(); + std::vector<gfx::Rect> highlighted_rects; + gfx::Rect visible_rect = GetVisibleRect(); for (const auto& range : selection_) { if (range.page_index() != page_index) continue; - const std::vector<pp::Rect>& rects = range.GetScreenRects( - PointFromPPPoint(visible_rect.point()), current_zoom_, - layout_.options().default_page_orientation()); + const std::vector<gfx::Rect>& rects = + range.GetScreenRects(visible_rect.origin(), current_zoom_, + layout_.options().default_page_orientation()); for (const auto& rect : rects) { - pp::Rect visible_selection = rect.Intersect(dirty_in_screen); + gfx::Rect visible_selection = gfx::IntersectRects(rect, dirty_in_screen); if (visible_selection.IsEmpty()) continue; - visible_selection.Offset(-dirty_in_screen.point().x(), - -dirty_in_screen.point().y()); + visible_selection.Offset(-dirty_in_screen.OffsetFromOrigin()); Highlight(region, stride, visible_selection, kHighlightColorR, - kHighlightColorG, kHighlightColorB, &highlighted_rects); + kHighlightColorG, kHighlightColorB, highlighted_rects); } } for (const auto& highlight : form_highlights_) { - pp::Rect visible_selection = highlight.Intersect(dirty_in_screen); + gfx::Rect visible_selection = + gfx::IntersectRects(highlight, dirty_in_screen); if (visible_selection.IsEmpty()) continue; - visible_selection.Offset(-dirty_in_screen.point().x(), - -dirty_in_screen.point().y()); + visible_selection.Offset(-dirty_in_screen.OffsetFromOrigin()); Highlight(region, stride, visible_selection, kHighlightColorR, - kHighlightColorG, kHighlightColorB, &highlighted_rects); + kHighlightColorG, kHighlightColorB, highlighted_rects); } } void PDFiumEngine::PaintUnavailablePage(int page_index, - const pp::Rect& dirty, + const gfx::Rect& dirty, SkBitmap& image_data) { int start_x; int start_y; @@ -3261,7 +3256,7 @@ void PDFiumEngine::PaintUnavailablePage(int page_index, FPDFBitmap_FillRect(bitmap.get(), start_x, start_y, size_x, size_y, kPendingPageColor); - pp::Rect loading_text_in_screen( + gfx::Rect loading_text_in_screen( pages_[page_index]->rect().width() / 2, pages_[page_index]->rect().y() + kLoadingTextVerticalOffset, 0, 0); loading_text_in_screen = GetScreenRect(loading_text_in_screen); @@ -3275,11 +3270,11 @@ int PDFiumEngine::GetProgressiveIndex(int page_index) const { return -1; } -ScopedFPDFBitmap PDFiumEngine::CreateBitmap(const pp::Rect& rect, +ScopedFPDFBitmap PDFiumEngine::CreateBitmap(const gfx::Rect& rect, SkBitmap& image_data) const { void* region; int stride; - GetRegion(PointFromPPPoint(rect.point()), image_data, region, stride); + GetRegion(rect.origin(), image_data, region, stride); if (!region) return nullptr; return ScopedFPDFBitmap(FPDFBitmap_CreateEx(rect.width(), rect.height(), @@ -3287,12 +3282,12 @@ ScopedFPDFBitmap PDFiumEngine::CreateBitmap(const pp::Rect& rect, } void PDFiumEngine::GetPDFiumRect(int page_index, - const pp::Rect& rect, + const gfx::Rect& rect, int* start_x, int* start_y, int* size_x, int* size_y) const { - pp::Rect page_rect = GetScreenRect(pages_[page_index]->rect()); + gfx::Rect page_rect = GetScreenRect(pages_[page_index]->rect()); page_rect.Offset(-rect.x(), -rect.y()); *start_x = page_rect.x(); @@ -3312,8 +3307,8 @@ int PDFiumEngine::GetRenderingFlags() const { return flags; } -pp::Rect PDFiumEngine::GetVisibleRect() const { - pp::Rect rv; +gfx::Rect PDFiumEngine::GetVisibleRect() const { + gfx::Rect rv; rv.set_x(static_cast<int>(position_.x() / current_zoom_)); rv.set_y(static_cast<int>(position_.y() / current_zoom_)); rv.set_width(static_cast<int>(ceil(plugin_size_.width() / current_zoom_))); @@ -3321,8 +3316,8 @@ pp::Rect PDFiumEngine::GetVisibleRect() const { return rv; } -pp::Rect PDFiumEngine::GetPageScreenRect(int page_index) const { - const pp::Rect& page_rect = pages_[page_index]->rect(); +gfx::Rect PDFiumEngine::GetPageScreenRect(int page_index) const { + gfx::Rect page_rect = pages_[page_index]->rect(); draw_utils::PageInsetSizes inset_sizes = GetInsetSizes(layout_.options(), page_index, pages_.size()); @@ -3339,33 +3334,33 @@ pp::Rect PDFiumEngine::GetPageScreenRect(int page_index) const { DocumentLayout::kBottomSeparator)); } -pp::Rect PDFiumEngine::GetScreenRect(const pp::Rect& rect) const { +gfx::Rect PDFiumEngine::GetScreenRect(const gfx::Rect& rect) const { return draw_utils::GetScreenRect(rect, position_, current_zoom_); } void PDFiumEngine::Highlight(void* buffer, int stride, - const pp::Rect& rect, + const gfx::Rect& rect, int color_red, int color_green, int color_blue, - std::vector<pp::Rect>* highlighted_rects) const { + std::vector<gfx::Rect>& highlighted_rects) const { if (!buffer) return; - pp::Rect new_rect = rect; - for (const auto& highlighted : *highlighted_rects) - new_rect = new_rect.Subtract(highlighted); + gfx::Rect new_rect = rect; + for (const auto& highlighted : highlighted_rects) + new_rect.Subtract(highlighted); if (new_rect.IsEmpty()) return; std::vector<size_t> overlapping_rect_indices; - for (size_t i = 0; i < highlighted_rects->size(); ++i) { - if (new_rect.Intersects((*highlighted_rects)[i])) + for (size_t i = 0; i < highlighted_rects.size(); ++i) { + if (new_rect.Intersects((highlighted_rects)[i])) overlapping_rect_indices.push_back(i); } - highlighted_rects->push_back(new_rect); + highlighted_rects.push_back(new_rect); int l = new_rect.x(); int t = new_rect.y(); int w = new_rect.width(); @@ -3375,7 +3370,7 @@ void PDFiumEngine::Highlight(void* buffer, for (int x = l; x < l + w; ++x) { bool overlaps = false; for (size_t i : overlapping_rect_indices) { - const auto& highlighted = (*highlighted_rects)[i]; + const auto& highlighted = (highlighted_rects)[i]; if (highlighted.Contains(x, y)) { overlaps = true; break; @@ -3395,23 +3390,22 @@ void PDFiumEngine::Highlight(void* buffer, PDFiumEngine::SelectionChangeInvalidator::SelectionChangeInvalidator( PDFiumEngine* engine) : engine_(engine), - previous_origin_(PointFromPPPoint(engine_->GetVisibleRect().point())), + previous_origin_(engine_->GetVisibleRect().origin()), old_selections_(GetVisibleSelections()) {} PDFiumEngine::SelectionChangeInvalidator::~SelectionChangeInvalidator() { // Offset the old selections if the document scrolled since we recorded them. - gfx::Vector2d offset = - previous_origin_ - RectFromPPRect(engine_->GetVisibleRect()).origin(); + gfx::Vector2d offset = previous_origin_ - engine_->GetVisibleRect().origin(); for (auto& old_selection : old_selections_) - old_selection.Offset(PPPointFromVector(offset)); + old_selection.Offset(offset); - std::vector<pp::Rect> new_selections = GetVisibleSelections(); + std::vector<gfx::Rect> new_selections = GetVisibleSelections(); for (auto& new_selection : new_selections) { for (auto& old_selection : old_selections_) { if (!old_selection.IsEmpty() && new_selection == old_selection) { // Rectangle was selected before and after, so no need to invalidate it. // Mark the rectangles by setting them to empty. - new_selection = old_selection = pp::Rect(); + new_selection = old_selection = gfx::Rect(); break; } } @@ -3437,17 +3431,16 @@ PDFiumEngine::SelectionChangeInvalidator::~SelectionChangeInvalidator() { } } -std::vector<pp::Rect> +std::vector<gfx::Rect> PDFiumEngine::SelectionChangeInvalidator::GetVisibleSelections() const { - std::vector<pp::Rect> rects; - gfx::Point visible_point = - PointFromPPPoint(engine_->GetVisibleRect().point()); + std::vector<gfx::Rect> rects; + gfx::Point visible_point = engine_->GetVisibleRect().origin(); for (const auto& range : engine_->selection_) { // Exclude selections on pages that's not currently visible. if (!engine_->IsPageVisible(range.page_index())) continue; - const std::vector<pp::Rect>& selection_rects = range.GetScreenRects( + const std::vector<gfx::Rect>& selection_rects = range.GetScreenRects( visible_point, engine_->current_zoom_, engine_->layout_.options().default_page_orientation()); rects.insert(rects.end(), selection_rects.begin(), selection_rects.end()); @@ -3456,8 +3449,8 @@ PDFiumEngine::SelectionChangeInvalidator::GetVisibleSelections() const { } void PDFiumEngine::SelectionChangeInvalidator::Invalidate( - const pp::Rect& selection) { - pp::Rect expanded_selection = selection; + const gfx::Rect& selection) { + gfx::Rect expanded_selection = selection; expanded_selection.Inset(-1, -1); engine_->client_->Invalidate(expanded_selection); } @@ -3545,18 +3538,18 @@ void PDFiumEngine::SetCurrentPage(int index) { } } -void PDFiumEngine::DrawPageShadow(const pp::Rect& page_rc, - const pp::Rect& shadow_rc, - const pp::Rect& clip_rc, +void PDFiumEngine::DrawPageShadow(const gfx::Rect& page_rc, + const gfx::Rect& shadow_rc, + const gfx::Rect& clip_rc, SkBitmap& image_data) { - pp::Rect page_rect(page_rc); - page_rect.Offset(PPPointFromVector(page_offset_)); + gfx::Rect page_rect(page_rc); + page_rect.Offset(page_offset_); - pp::Rect shadow_rect(shadow_rc); - shadow_rect.Offset(PPPointFromVector(page_offset_)); + gfx::Rect shadow_rect(shadow_rc); + shadow_rect.Offset(page_offset_); - pp::Rect clip_rect(clip_rc); - clip_rect.Offset(PPPointFromVector(page_offset_)); + gfx::Rect clip_rect(clip_rc); + clip_rect.Offset(page_offset_); // Page drop shadow parameters. constexpr double factor = 0.5; @@ -3612,13 +3605,13 @@ void PDFiumEngine::OnSelectionPositionChanged() { // We need to determine the top-left and bottom-right points of the selection // in order to report those to the embedder. This code assumes that the // selection list is out of order. - pp::Rect left(std::numeric_limits<int32_t>::max(), - std::numeric_limits<int32_t>::max(), 0, 0); - pp::Rect right; + gfx::Rect left(std::numeric_limits<int32_t>::max(), + std::numeric_limits<int32_t>::max(), 0, 0); + gfx::Rect right; for (const auto& sel : selection_) { - const std::vector<pp::Rect>& screen_rects = sel.GetScreenRects( - PointFromPPPoint(GetVisibleRect().point()), current_zoom_, - layout_.options().default_page_orientation()); + const std::vector<gfx::Rect>& screen_rects = + sel.GetScreenRects(GetVisibleRect().origin(), current_zoom_, + layout_.options().default_page_orientation()); for (const auto& rect : screen_rects) { if (IsAboveOrDirectlyLeftOf(rect, left)) left = rect; @@ -3812,12 +3805,12 @@ void PDFiumEngine::ScrollAnnotationIntoView(FPDF_ANNOTATION annot, if (!FPDFAnnot_GetRect(annot, &annot_rect)) return; - pp::Rect rect = pages_[page_index]->PageToScreen( + gfx::Rect rect = pages_[page_index]->PageToScreen( gfx::Point(), /*zoom=*/1.0, annot_rect.left, annot_rect.top, annot_rect.right, annot_rect.bottom, layout_.options().default_page_orientation()); - pp::Rect visible_rect = GetVisibleRect(); + gfx::Rect visible_rect = GetVisibleRect(); if (visible_rect.Contains(rect)) return; // Since the focus rect is not already in the visible area, scrolling @@ -4004,14 +3997,13 @@ PdfVersion PDFiumEngine::GetDocumentVersion() const { } bool PDFiumEngine::HandleTabEvent(uint32_t modifiers) { - bool alt_key = !!(modifiers & PP_INPUTEVENT_MODIFIER_ALTKEY); - bool ctrl_key = !!(modifiers & PP_INPUTEVENT_MODIFIER_CONTROLKEY); + bool alt_key = !!(modifiers & kInputEventModifierAltKey); + bool ctrl_key = !!(modifiers & kInputEventModifierControlKey); if (alt_key || ctrl_key) return HandleTabEventWithModifiers(modifiers); - return modifiers & PP_INPUTEVENT_MODIFIER_SHIFTKEY - ? HandleTabBackward(modifiers) - : HandleTabForward(modifiers); + return modifiers & kInputEventModifierShiftKey ? HandleTabBackward(modifiers) + : HandleTabForward(modifiers); } bool PDFiumEngine::HandleTabEventWithModifiers(uint32_t modifiers) { @@ -4147,8 +4139,16 @@ void PDFiumEngine::SetLinkUnderCursorForAnnotation(FPDF_ANNOTATION annot, UpdateLinkUnderCursor(target.url); } +void PDFiumEngine::RequestThumbnail(int page_index, + float device_pixel_ratio, + SendThumbnailCallback send_callback) { + DCHECK(PageIndexInBounds(page_index)); + pages_[page_index]->RequestThumbnail(device_pixel_ratio, + std::move(send_callback)); +} + PDFiumEngine::ProgressivePaint::ProgressivePaint(int index, - const pp::Rect& rect) + const gfx::Rect& rect) : page_index_(index), rect_(rect) {} PDFiumEngine::ProgressivePaint::ProgressivePaint(ProgressivePaint&& that) = diff --git a/chromium/pdf/pdfium/pdfium_engine.h b/chromium/pdf/pdfium/pdfium_engine.h index ef023c90aa6..dc2a9853fb4 100644 --- a/chromium/pdf/pdfium/pdfium_engine.h +++ b/chromium/pdf/pdfium/pdfium_engine.h @@ -28,8 +28,6 @@ #include "pdf/pdfium/pdfium_range.h" #include "ppapi/c/private/ppp_pdf.h" #include "ppapi/cpp/dev/buffer_dev.h" -#include "ppapi/cpp/input_event.h" -#include "ppapi/cpp/rect.h" #include "ppapi/cpp/var_array.h" #include "third_party/pdfium/public/cpp/fpdf_scopers.h" #include "third_party/pdfium/public/fpdf_formfill.h" @@ -37,6 +35,7 @@ #include "third_party/pdfium/public/fpdfview.h" #include "third_party/skia/include/core/SkBitmap.h" #include "ui/gfx/geometry/point.h" +#include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/size.h" #include "ui/gfx/geometry/vector2d.h" @@ -63,7 +62,9 @@ class PDFiumEngine : public PDFEngine, // Exposed for testing. enum class FocusElementType { kNone, kDocument, kPage }; - PDFiumEngine(PDFEngine::Client* client, bool enable_javascript); + // NOTE: |script_option| is ignored when PDF_ENABLE_V8 is not defined. + PDFiumEngine(PDFEngine::Client* client, + PDFiumFormFiller::ScriptOption script_option); PDFiumEngine(const PDFiumEngine&) = delete; PDFiumEngine& operator=(const PDFiumEngine&) = delete; ~PDFiumEngine() override; @@ -89,13 +90,13 @@ class PDFiumEngine : public PDFEngine, void ScrolledToXPosition(int position) override; void ScrolledToYPosition(int position) override; void PrePaint() override; - void Paint(const pp::Rect& rect, + void Paint(const gfx::Rect& rect, SkBitmap& image_data, - std::vector<pp::Rect>& ready, - std::vector<pp::Rect>& pending) override; + std::vector<gfx::Rect>& ready, + std::vector<gfx::Rect>& pending) override; void PostPaint() override; - bool HandleDocumentLoad(const pp::URLLoader& loader) override; - bool HandleEvent(const pp::InputEvent& event) override; + bool HandleDocumentLoad(std::unique_ptr<UrlLoader> loader) override; + bool HandleEvent(const InputEvent& event) override; uint32_t QuerySupportedPrintOutputFormats() override; void PrintBegin() override; pp::Resource PrintPages( @@ -136,13 +137,13 @@ class PDFiumEngine : public PDFEngine, base::Optional<PDFEngine::NamedDestination> GetNamedDestination( const std::string& destination) override; int GetMostVisiblePage() override; - pp::Rect GetPageBoundsRect(int index) override; - pp::Rect GetPageContentsRect(int index) override; - pp::Rect GetPageScreenRect(int page_index) const override; + gfx::Rect GetPageBoundsRect(int index) override; + gfx::Rect GetPageContentsRect(int index) override; + gfx::Rect GetPageScreenRect(int page_index) const override; int GetVerticalScrollbarYPosition() override; void SetGrayscale(bool grayscale) override; int GetCharCount(int page_index) override; - pp::FloatRect GetCharBounds(int page_index, int char_index) override; + gfx::RectF GetCharBounds(int page_index, int char_index) override; uint32_t GetCharUnicode(int page_index, int char_index) override; base::Optional<pp::PDF::PrivateAccessibilityTextRunInfo> GetTextRunInfo( int page_index, @@ -173,6 +174,9 @@ class PDFiumEngine : public PDFEngine, PP_PrivateAccessibilityFocusInfo GetFocusInfo() override; uint32_t GetLoadedByteSize() override; bool ReadLoadedBytes(uint32_t length, void* buffer) override; + void RequestThumbnail(int page_index, + float device_pixel_ratio, + SendThumbnailCallback send_callback) override; // DocumentLoader::Client: pp::Instance* GetPluginInstance() override; @@ -205,17 +209,17 @@ class PDFiumEngine : public PDFEngine, private: // Returns all the currently visible selection rectangles, in screen // coordinates. - std::vector<pp::Rect> GetVisibleSelections() const; + std::vector<gfx::Rect> GetVisibleSelections() const; // Invalidates |selection|, but with |selection| slightly expanded to // compensate for any rounding errors. - void Invalidate(const pp::Rect& selection); + void Invalidate(const gfx::Rect& selection); PDFiumEngine* const engine_; // The origin at the time this object was constructed. const gfx::Point previous_origin_; // Screen rectangles that were selected on construction. - std::vector<pp::Rect> old_selections_; + std::vector<gfx::Rect> old_selections_; }; // Used to store mouse down state to handle it in other mouse event handlers. @@ -349,7 +353,7 @@ class PDFiumEngine : public PDFEngine, size_t page_index, size_t num_of_pages, double multiplier, - pp::Rect* rect) const; + gfx::Rect& rect) const; // If two-up view is enabled, returns the index of the page beside // |page_index| page. Returns base::nullopt if there is no adjacent page or @@ -358,7 +362,7 @@ class PDFiumEngine : public PDFEngine, size_t page_index, size_t num_of_pages) const; - std::vector<pp::Rect> GetAllScreenRectsUnion( + std::vector<gfx::Rect> GetAllScreenRectsUnion( const std::vector<PDFiumRange>& rect_range, const gfx::Point& point) const; @@ -434,7 +438,7 @@ class PDFiumEngine : public PDFEngine, // Starts a progressive paint operation given a rectangle in screen // coordinates. Returns the index in progressive_rects_. - int StartPaint(int page_index, const pp::Rect& dirty); + int StartPaint(int page_index, const gfx::Rect& dirty); // Continues a paint operation that was started earlier. Returns true if the // paint is done, or false if it needs to be continued. @@ -462,7 +466,7 @@ class PDFiumEngine : public PDFEngine, // Paints an page that hasn't finished downloading. void PaintUnavailablePage(int page_index, - const pp::Rect& dirty, + const gfx::Rect& dirty, SkBitmap& image_data); // Given a page index, returns the corresponding index in progressive_rects_, @@ -470,13 +474,13 @@ class PDFiumEngine : public PDFEngine, int GetProgressiveIndex(int page_index) const; // Creates a FPDF_BITMAP from a rectangle in screen coordinates. - ScopedFPDFBitmap CreateBitmap(const pp::Rect& rect, + ScopedFPDFBitmap CreateBitmap(const gfx::Rect& rect, SkBitmap& image_data) const; // Given a rectangle in screen coordinates, returns the coordinates in the // units that PDFium rendering functions expect. void GetPDFiumRect(int page_index, - const pp::Rect& rect, + const gfx::Rect& rect, int* start_x, int* start_y, int* size_x, @@ -486,22 +490,22 @@ class PDFiumEngine : public PDFEngine, int GetRenderingFlags() const; // Returns the currently visible rectangle in document coordinates. - pp::Rect GetVisibleRect() const; + gfx::Rect GetVisibleRect() const; // Given |rect| in document coordinates, returns the rectangle in screen // coordinates. (i.e. 0,0 is top left corner of plugin area) - pp::Rect GetScreenRect(const pp::Rect& rect) const; + gfx::Rect GetScreenRect(const gfx::Rect& rect) const; // Given an image |buffer| with |stride|, highlights |rect|. // |highlighted_rects| contains the already highlighted rectangles and will be // updated to include |rect| if |rect| has not already been highlighted. void Highlight(void* buffer, int stride, - const pp::Rect& rect, + const gfx::Rect& rect, int color_red, int color_green, int color_blue, - std::vector<pp::Rect>* highlighted_rects) const; + std::vector<gfx::Rect>& highlighted_rects) const; // Helper function to convert a device to page coordinates. If the page is // not yet loaded, |page_x| and |page_y| will be set to 0. @@ -518,9 +522,9 @@ class PDFiumEngine : public PDFEngine, // triggers as necessary. void SetCurrentPage(int index); - void DrawPageShadow(const pp::Rect& page_rect, - const pp::Rect& shadow_rect, - const pp::Rect& clip_rect, + void DrawPageShadow(const gfx::Rect& page_rect, + const gfx::Rect& shadow_rect, + const gfx::Rect& clip_rect, SkBitmap& image_data); void GetRegion(const gfx::Point& location, @@ -568,13 +572,13 @@ class PDFiumEngine : public PDFEngine, unsigned int depth); void ScrollBasedOnScrollAlignment( - const pp::Rect& scroll_rect, + const gfx::Rect& scroll_rect, const PP_PdfAccessibilityScrollAlignment& horizontal_scroll_alignment, const PP_PdfAccessibilityScrollAlignment& vertical_scroll_alignment); // Scrolls top left of a rect in page |target_rect| to |global_point|. // Global point is point relative to viewport in screen. - void ScrollToGlobalPoint(const pp::Rect& target_rect, + void ScrollToGlobalPoint(const gfx::Rect& target_rect, const gfx::Point& global_point); // Set if the document has any local edits. @@ -765,7 +769,7 @@ class PDFiumEngine : public PDFEngine, // Records parts of form fields that need to be highlighted at next paint, in // screen coordinates. - std::vector<pp::Rect> form_highlights_; + std::vector<gfx::Rect> form_highlights_; // Whether to render in grayscale or in color. bool render_grayscale_ = false; @@ -779,13 +783,13 @@ class PDFiumEngine : public PDFEngine, // Pending progressive paints. class ProgressivePaint { public: - ProgressivePaint(int page_index, const pp::Rect& rect); + ProgressivePaint(int page_index, const gfx::Rect& rect); ProgressivePaint(ProgressivePaint&& that); ProgressivePaint& operator=(ProgressivePaint&& that); ~ProgressivePaint(); int page_index() const { return page_index_; } - const pp::Rect& rect() const { return rect_; } + const gfx::Rect& rect() const { return rect_; } FPDF_BITMAP bitmap() const { return bitmap_.get(); } bool painted() const { return painted_; } @@ -794,7 +798,7 @@ class PDFiumEngine : public PDFEngine, private: int page_index_; - pp::Rect rect_; // In screen coordinates. + gfx::Rect rect_; // In screen coordinates. SkBitmap image_data_; // Maintains reference while |bitmap_| exists. ScopedFPDFBitmap bitmap_; // Must come after |image_data_|. // Temporary used to figure out if in a series of Paint() calls whether this diff --git a/chromium/pdf/pdfium/pdfium_engine_exports.cc b/chromium/pdf/pdfium/pdfium_engine_exports.cc index c62c0b0d9d1..fe9d8a27208 100644 --- a/chromium/pdf/pdfium/pdfium_engine_exports.cc +++ b/chromium/pdf/pdfium/pdfium_engine_exports.cc @@ -10,10 +10,10 @@ #include "base/bind.h" #include "base/no_destructor.h" #include "base/numerics/safe_conversions.h" +#include "base/optional.h" #include "pdf/pdfium/pdfium_api_string_buffer_adapter.h" #include "pdf/pdfium/pdfium_mem_buffer_file_write.h" #include "pdf/pdfium/pdfium_print.h" -#include "pdf/ppapi_migration/geometry_conversions.h" #include "printing/nup_parameters.h" #include "printing/units.h" #include "third_party/pdfium/public/cpp/fpdf_scopers.h" @@ -23,6 +23,7 @@ #include "third_party/pdfium/public/fpdfview.h" #include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/size.h" +#include "ui/gfx/geometry/size_f.h" #include "ui/gfx/geometry/vector2d.h" using printing::ConvertUnitDouble; @@ -34,13 +35,15 @@ namespace { int CalculatePosition(FPDF_PAGE page, const PDFiumEngineExports::RenderingSettings& settings, - pp::Rect* dest) { + gfx::Rect* dest) { // settings.bounds is in terms of the max DPI. Convert page sizes to match. - int dpi = std::max(settings.dpi_x, settings.dpi_y); + const int dpi_x = settings.dpi.width(); + const int dpi_y = settings.dpi.height(); + const int dpi = std::max(dpi_x, dpi_y); int page_width = static_cast<int>( - ConvertUnitDouble(FPDF_GetPageWidth(page), kPointsPerInch, dpi)); + ConvertUnitDouble(FPDF_GetPageWidthF(page), kPointsPerInch, dpi)); int page_height = static_cast<int>( - ConvertUnitDouble(FPDF_GetPageHeight(page), kPointsPerInch, dpi)); + ConvertUnitDouble(FPDF_GetPageHeightF(page), kPointsPerInch, dpi)); // Start by assuming that we will draw exactly to the bounds rect // specified. @@ -88,16 +91,16 @@ int CalculatePosition(FPDF_PAGE page, } // Scale the bounds to device units if DPI is rectangular. - if (settings.dpi_x != settings.dpi_y) { - dest->set_width(dest->width() * settings.dpi_x / dpi); - dest->set_height(dest->height() * settings.dpi_y / dpi); + if (dpi_x != dpi_y) { + dest->set_width(dest->width() * dpi_x / dpi); + dest->set_height(dest->height() * dpi_y / dpi); } if (settings.center_in_bounds) { gfx::Vector2d offset( - (settings.bounds.width() * settings.dpi_x / dpi - dest->width()) / 2, - (settings.bounds.height() * settings.dpi_y / dpi - dest->height()) / 2); - dest->Offset(PPPointFromVector(offset)); + (settings.bounds.width() * dpi_x / dpi - dest->width()) / 2, + (settings.bounds.height() * dpi_y / dpi - dest->height()) / 2); + dest->Offset(offset); } return rotate; } @@ -134,6 +137,16 @@ bool IsValidPrintableArea(const gfx::Size& page_size, printable_area.bottom() <= page_size.height(); } +int GetRenderFlagsFromSettings( + const PDFiumEngineExports::RenderingSettings& settings) { + int flags = FPDF_ANNOT; + if (!settings.use_color) + flags |= FPDF_GRAYSCALE; + if (settings.render_for_printing) + flags |= FPDF_PRINTING; + return flags; +} + base::Value RecursiveGetStructTree(FPDF_STRUCTELEMENT struct_elem) { int children_count = FPDF_StructElement_CountChildren(struct_elem); if (children_count <= 0) @@ -182,24 +195,24 @@ base::Value RecursiveGetStructTree(FPDF_STRUCTELEMENT struct_elem) { } // namespace -PDFEngineExports::RenderingSettings::RenderingSettings(int dpi_x, - int dpi_y, - const pp::Rect& bounds, +PDFEngineExports::RenderingSettings::RenderingSettings(const gfx::Size& dpi, + const gfx::Rect& bounds, bool fit_to_bounds, bool stretch_to_bounds, bool keep_aspect_ratio, bool center_in_bounds, bool autorotate, - bool use_color) - : dpi_x(dpi_x), - dpi_y(dpi_y), + bool use_color, + bool render_for_printing) + : dpi(dpi), bounds(bounds), fit_to_bounds(fit_to_bounds), stretch_to_bounds(stretch_to_bounds), keep_aspect_ratio(keep_aspect_ratio), center_in_bounds(center_in_bounds), autorotate(autorotate), - use_color(use_color) {} + use_color(use_color), + render_for_printing(render_for_printing) {} PDFEngineExports::RenderingSettings::RenderingSettings( const RenderingSettings& that) = default; @@ -238,12 +251,12 @@ bool PDFiumEngineExports::RenderPDFPageToDC( RenderingSettings new_settings = settings; // calculate the page size - if (new_settings.dpi_x == -1) - new_settings.dpi_x = GetDeviceCaps(dc, LOGPIXELSX); - if (new_settings.dpi_y == -1) - new_settings.dpi_y = GetDeviceCaps(dc, LOGPIXELSY); + if (new_settings.dpi.width() == -1) + new_settings.dpi.set_width(GetDeviceCaps(dc, LOGPIXELSX)); + if (new_settings.dpi.height() == -1) + new_settings.dpi.set_height(GetDeviceCaps(dc, LOGPIXELSY)); - pp::Rect dest; + gfx::Rect dest; int rotate = CalculatePosition(page.get(), new_settings, &dest); int save_state = SaveDC(dc); @@ -254,9 +267,7 @@ bool PDFiumEngineExports::RenderPDFPageToDC( settings.bounds.x() + settings.bounds.width(), settings.bounds.y() + settings.bounds.height()); - int flags = FPDF_ANNOT | FPDF_PRINTING; - if (!settings.use_color) - flags |= FPDF_GRAYSCALE; + int flags = GetRenderFlagsFromSettings(settings); // A "temporary" hack. Some PDFs seems to render very slowly if // FPDF_RenderPage() is directly used on a printer DC. I suspect it is @@ -322,7 +333,7 @@ bool PDFiumEngineExports::RenderPDFPageToBitmap( if (!page) return false; - pp::Rect dest; + gfx::Rect dest; int rotate = CalculatePosition(page.get(), settings, &dest); ScopedFPDFBitmap bitmap(FPDFBitmap_CreateEx( @@ -332,14 +343,11 @@ bool PDFiumEngineExports::RenderPDFPageToBitmap( FPDFBitmap_FillRect(bitmap.get(), 0, 0, settings.bounds.width(), settings.bounds.height(), 0xFFFFFFFF); // Shift top-left corner of bounds to (0, 0) if it's not there. - dest.set_point(dest.point() - settings.bounds.point()); - - int flags = FPDF_ANNOT | FPDF_PRINTING; - if (!settings.use_color) - flags |= FPDF_GRAYSCALE; + dest.set_origin(dest.origin() - settings.bounds.OffsetFromOrigin()); FPDF_RenderPageBitmap(bitmap.get(), page.get(), dest.x(), dest.y(), - dest.width(), dest.height(), rotate, flags); + dest.width(), dest.height(), rotate, + GetRenderFlagsFromSettings(settings)); return true; } @@ -377,7 +385,7 @@ std::vector<uint8_t> PDFiumEngineExports::ConvertPdfDocumentToNupPdf( bool PDFiumEngineExports::GetPDFDocInfo(base::span<const uint8_t> pdf_buffer, int* page_count, - double* max_page_width) { + float* max_page_width) { ScopedFPDFDocument doc = LoadPdfData(pdf_buffer); if (!doc) return false; @@ -392,12 +400,10 @@ bool PDFiumEngineExports::GetPDFDocInfo(base::span<const uint8_t> pdf_buffer, if (max_page_width) { *max_page_width = 0; for (int page_number = 0; page_number < page_count_local; page_number++) { - double page_width = 0; - double page_height = 0; - FPDF_GetPageSizeByIndex(doc.get(), page_number, &page_width, - &page_height); - if (page_width > *max_page_width) { - *max_page_width = page_width; + FS_SIZEF page_size; + if (FPDF_GetPageSizeByIndexF(doc.get(), page_number, &page_size) && + page_size.width > *max_page_width) { + *max_page_width = page_size.width; } } } @@ -441,15 +447,18 @@ base::Value PDFiumEngineExports::GetPDFStructTreeForPage( return RecursiveGetStructTree(struct_root_elem); } -bool PDFiumEngineExports::GetPDFPageSizeByIndex( +base::Optional<gfx::SizeF> PDFiumEngineExports::GetPDFPageSizeByIndex( base::span<const uint8_t> pdf_buffer, - int page_number, - double* width, - double* height) { + int page_number) { ScopedFPDFDocument doc = LoadPdfData(pdf_buffer); if (!doc) - return false; - return FPDF_GetPageSizeByIndex(doc.get(), page_number, width, height) != 0; + return base::nullopt; + + FS_SIZEF size; + if (!FPDF_GetPageSizeByIndexF(doc.get(), page_number, &size)) + return base::nullopt; + + return gfx::SizeF(size.width, size.height); } } // namespace chrome_pdf diff --git a/chromium/pdf/pdfium/pdfium_engine_exports.h b/chromium/pdf/pdfium/pdfium_engine_exports.h index 6f5f07529b7..e0004e1e386 100644 --- a/chromium/pdf/pdfium/pdfium_engine_exports.h +++ b/chromium/pdf/pdfium/pdfium_engine_exports.h @@ -52,15 +52,14 @@ class PDFiumEngineExports : public PDFEngineExports { const gfx::Rect& printable_area) override; bool GetPDFDocInfo(base::span<const uint8_t> pdf_buffer, int* page_count, - double* max_page_width) override; + float* max_page_width) override; base::Optional<bool> IsPDFDocTagged( base::span<const uint8_t> pdf_buffer) override; base::Value GetPDFStructTreeForPage(base::span<const uint8_t> pdf_buffer, int page_index) override; - bool GetPDFPageSizeByIndex(base::span<const uint8_t> pdf_buffer, - int page_number, - double* width, - double* height) override; + base::Optional<gfx::SizeF> GetPDFPageSizeByIndex( + base::span<const uint8_t> pdf_buffer, + int page_number) override; }; } // namespace chrome_pdf diff --git a/chromium/pdf/pdfium/pdfium_engine_exports_unittest.cc b/chromium/pdf/pdfium/pdfium_engine_exports_unittest.cc index 012b2caa453..189504a58b4 100644 --- a/chromium/pdf/pdfium/pdfium_engine_exports_unittest.cc +++ b/chromium/pdf/pdfium/pdfium_engine_exports_unittest.cc @@ -3,6 +3,7 @@ // found in the LICENSE file. #include "base/files/file_util.h" +#include "base/optional.h" #include "base/path_service.h" #include "base/test/test_simple_task_runner.h" #include "base/threading/thread_task_runner_handle.h" @@ -11,6 +12,7 @@ #include "testing/gtest/include/gtest/gtest.h" #include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/size.h" +#include "ui/gfx/geometry/size_f.h" namespace chrome_pdf { @@ -65,7 +67,7 @@ TEST_F(PDFiumEngineExportsTest, GetPDFDocInfo) { ASSERT_TRUE(GetPDFDocInfo(pdf_span, nullptr, nullptr)); int page_count; - double max_page_width; + float max_page_width; ASSERT_TRUE(GetPDFDocInfo(pdf_span, &page_count, &max_page_width)); EXPECT_EQ(2, page_count); EXPECT_DOUBLE_EQ(200.0, max_page_width); @@ -80,17 +82,14 @@ TEST_F(PDFiumEngineExportsTest, GetPDFPageSizeByIndex) { ASSERT_TRUE(base::ReadFileToString(pdf_path, &pdf_data)); auto pdf_span = base::as_bytes(base::make_span(pdf_data)); - EXPECT_FALSE(GetPDFPageSizeByIndex(pdf_span, 0, nullptr, nullptr)); - int page_count; ASSERT_TRUE(GetPDFDocInfo(pdf_span, &page_count, nullptr)); ASSERT_EQ(2, page_count); for (int page_number = 0; page_number < page_count; ++page_number) { - double width; - double height; - ASSERT_TRUE(GetPDFPageSizeByIndex(pdf_span, page_number, &width, &height)); - EXPECT_DOUBLE_EQ(200.0, width); - EXPECT_DOUBLE_EQ(200.0, height); + base::Optional<gfx::SizeF> page_size = + GetPDFPageSizeByIndex(pdf_span, page_number); + ASSERT_TRUE(page_size.has_value()); + EXPECT_EQ(gfx::SizeF(200, 200), page_size.value()); } } @@ -129,11 +128,10 @@ TEST_F(PDFiumEngineExportsTest, ConvertPdfPagesToNupPdf) { ASSERT_TRUE(GetPDFDocInfo(output_pdf_span, &page_count, nullptr)); ASSERT_EQ(1, page_count); - double width; - double height; - ASSERT_TRUE(GetPDFPageSizeByIndex(output_pdf_span, 0, &width, &height)); - EXPECT_DOUBLE_EQ(792.0, width); - EXPECT_DOUBLE_EQ(612.0, height); + base::Optional<gfx::SizeF> page_size = + GetPDFPageSizeByIndex(output_pdf_span, 0); + ASSERT_TRUE(page_size.has_value()); + EXPECT_EQ(gfx::SizeF(792, 612), page_size.value()); } TEST_F(PDFiumEngineExportsTest, ConvertPdfDocumentToNupPdf) { @@ -158,12 +156,10 @@ TEST_F(PDFiumEngineExportsTest, ConvertPdfDocumentToNupPdf) { ASSERT_TRUE(GetPDFDocInfo(output_pdf_span, &page_count, nullptr)); ASSERT_EQ(2, page_count); for (int page_number = 0; page_number < page_count; ++page_number) { - double width; - double height; - ASSERT_TRUE( - GetPDFPageSizeByIndex(output_pdf_span, page_number, &width, &height)); - EXPECT_DOUBLE_EQ(612.0, width); - EXPECT_DOUBLE_EQ(792.0, height); + base::Optional<gfx::SizeF> page_size = + GetPDFPageSizeByIndex(output_pdf_span, page_number); + ASSERT_TRUE(page_size.has_value()); + EXPECT_EQ(gfx::SizeF(612, 792), page_size.value()); } } diff --git a/chromium/pdf/pdfium/pdfium_engine_unittest.cc b/chromium/pdf/pdfium/pdfium_engine_unittest.cc index 66452b447c6..5d92c299b3f 100644 --- a/chromium/pdf/pdfium/pdfium_engine_unittest.cc +++ b/chromium/pdf/pdfium/pdfium_engine_unittest.cc @@ -8,6 +8,8 @@ #include "base/hash/md5.h" #include "base/strings/utf_string_conversions.h" +#include "base/test/gtest_util.h" +#include "base/test/mock_callback.h" #include "base/test/scoped_feature_list.h" #include "base/test/task_environment.h" #include "pdf/document_attachment_info.h" @@ -16,13 +18,14 @@ #include "pdf/pdf_features.h" #include "pdf/pdfium/pdfium_page.h" #include "pdf/pdfium/pdfium_test_base.h" +#include "pdf/ppapi_migration/input_event_conversions.h" #include "pdf/test/test_client.h" #include "pdf/test/test_document_loader.h" -#include "pdf/test/test_utils.h" -#include "ppapi/c/ppb_input_event.h" -#include "ppapi/cpp/size.h" +#include "pdf/thumbnail.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" +#include "ui/gfx/geometry/point.h" +#include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/size.h" namespace chrome_pdf { @@ -66,9 +69,9 @@ class PDFiumEngineTest : public PDFiumTestBase { protected: void ExpectPageRect(const PDFiumEngine& engine, size_t page_index, - const pp::Rect& expected_rect) { + const gfx::Rect& expected_rect) { const PDFiumPage& page = GetPDFiumPageForTest(engine, page_index); - CompareRect(expected_rect, page.rect()); + EXPECT_EQ(expected_rect, page.rect()); } // Tries to load a PDF incrementally, returning `true` if the PDF actually was @@ -111,7 +114,6 @@ class PDFiumEngineTest : public PDFiumTestBase { return loaded_incrementally; } - private: // Counts the number of available pages. Returns `int` instead of `size_t` for // consistency with `PDFiumEngine::GetNumberOfPages()`. int CountAvailablePages(const PDFiumEngine& engine) { @@ -395,6 +397,88 @@ TEST_F(PDFiumEngineTest, IncrementalLoadingFeatureDisabled) { EXPECT_FALSE(TryLoadIncrementally()); } +TEST_F(PDFiumEngineTest, RequestThumbnail) { + TestClient client; + std::unique_ptr<PDFiumEngine> engine = InitializeEngine( + &client, FILE_PATH_LITERAL("rectangles_multi_pages.pdf")); + ASSERT_TRUE(engine); + + const int num_pages = engine->GetNumberOfPages(); + ASSERT_EQ(5, num_pages); + ASSERT_EQ(num_pages, CountAvailablePages(*engine)); + + // Each page should immediately return a thumbnail. + for (int i = 0; i < num_pages; ++i) { + base::MockCallback<SendThumbnailCallback> send_callback; + EXPECT_CALL(send_callback, Run); + engine->RequestThumbnail(/*page_index=*/i, /*device_pixel_ratio=*/1, + send_callback.Get()); + } +} + +TEST_F(PDFiumEngineTest, RequestThumbnailLinearized) { + NiceMock<MockTestClient> client; + InitializeEngineResult initialize_result = InitializeEngineWithoutLoading( + &client, FILE_PATH_LITERAL("linearized.pdf")); + ASSERT_TRUE(initialize_result.engine); + PDFiumEngine& engine = *initialize_result.engine; + + // Load only some pages. + initialize_result.document_loader->SimulateLoadData(8192); + + // Note: Plugin size chosen so all pages of the document are visible. The + // engine only updates availability incrementally for visible pages. + engine.PluginSizeUpdated({1024, 4096}); + + const int num_pages = engine.GetNumberOfPages(); + ASSERT_EQ(3, num_pages); + const int available_pages = CountAvailablePages(engine); + ASSERT_LT(0, available_pages); + ASSERT_GT(num_pages, available_pages); + + // Initialize callbacks for first and last pages. + base::MockCallback<SendThumbnailCallback> first_loaded; + base::MockCallback<SendThumbnailCallback> last_loaded; + + // When the document is partially loaded, `SendThumbnailCallback` is only run + // for the loaded page even though `RequestThumbnail()` gets called for both + // pages. + EXPECT_CALL(first_loaded, Run); + engine.RequestThumbnail(/*page_index=*/0, /*device_pixel_ratio=*/1, + first_loaded.Get()); + engine.RequestThumbnail(/*page_index=*/num_pages - 1, + /*device_pixel_ratio=*/1, last_loaded.Get()); + + // Finish loading the document. `SendThumbnailCallback` should be run for the + // last page. + EXPECT_CALL(last_loaded, Run); + while (initialize_result.document_loader->SimulateLoadData(UINT32_MAX)) + continue; +} + +using PDFiumEngineDeathTest = PDFiumEngineTest; + +TEST_F(PDFiumEngineDeathTest, RequestThumbnailRedundant) { + ::testing::FLAGS_gtest_death_test_style = "threadsafe"; + + NiceMock<MockTestClient> client; + InitializeEngineResult initialize_result = InitializeEngineWithoutLoading( + &client, FILE_PATH_LITERAL("linearized.pdf")); + ASSERT_TRUE(initialize_result.engine); + PDFiumEngine& engine = *initialize_result.engine; + + // Load only some pages. + initialize_result.document_loader->SimulateLoadData(8192); + + // Twice request a thumbnail for the second page, which is not loaded. The + // second call should crash. + base::MockCallback<SendThumbnailCallback> mock_callback; + engine.RequestThumbnail(/*page_index=*/1, /*device_pixel_ratio=*/1, + mock_callback.Get()); + EXPECT_DCHECK_DEATH(engine.RequestThumbnail( + /*page_index=*/1, /*device_pixel_ratio=*/1, mock_callback.Get())); +} + class TabbingTestClient : public TestClient { public: TabbingTestClient() = default; @@ -489,7 +573,7 @@ TEST_F(PDFiumEngineTabbingTest, LinkUnderCursorTest) { EXPECT_EQ("https://www.google.com/", GetLinkUnderCursor(engine.get())); // Tab to previous annotation. - ASSERT_TRUE(HandleTabEvent(engine.get(), PP_INPUTEVENT_MODIFIER_SHIFTKEY)); + ASSERT_TRUE(HandleTabEvent(engine.get(), kInputEventModifierShiftKey)); EXPECT_EQ("", GetLinkUnderCursor(engine.get())); } @@ -629,26 +713,26 @@ TEST_F(PDFiumEngineTabbingTest, TabbingBackwardTest) { GetFocusedElementType(engine.get())); EXPECT_EQ(-1, GetLastFocusedPage(engine.get())); - ASSERT_TRUE(HandleTabEvent(engine.get(), PP_INPUTEVENT_MODIFIER_SHIFTKEY)); + ASSERT_TRUE(HandleTabEvent(engine.get(), kInputEventModifierShiftKey)); EXPECT_EQ(PDFiumEngine::FocusElementType::kPage, GetFocusedElementType(engine.get())); EXPECT_EQ(1, GetLastFocusedPage(engine.get())); - ASSERT_TRUE(HandleTabEvent(engine.get(), PP_INPUTEVENT_MODIFIER_SHIFTKEY)); + ASSERT_TRUE(HandleTabEvent(engine.get(), kInputEventModifierShiftKey)); EXPECT_EQ(PDFiumEngine::FocusElementType::kPage, GetFocusedElementType(engine.get())); EXPECT_EQ(0, GetLastFocusedPage(engine.get())); - ASSERT_TRUE(HandleTabEvent(engine.get(), PP_INPUTEVENT_MODIFIER_SHIFTKEY)); + ASSERT_TRUE(HandleTabEvent(engine.get(), kInputEventModifierShiftKey)); EXPECT_EQ(PDFiumEngine::FocusElementType::kPage, GetFocusedElementType(engine.get())); EXPECT_EQ(0, GetLastFocusedPage(engine.get())); - ASSERT_TRUE(HandleTabEvent(engine.get(), PP_INPUTEVENT_MODIFIER_SHIFTKEY)); + ASSERT_TRUE(HandleTabEvent(engine.get(), kInputEventModifierShiftKey)); EXPECT_EQ(PDFiumEngine::FocusElementType::kDocument, GetFocusedElementType(engine.get())); - ASSERT_FALSE(HandleTabEvent(engine.get(), PP_INPUTEVENT_MODIFIER_SHIFTKEY)); + ASSERT_FALSE(HandleTabEvent(engine.get(), kInputEventModifierShiftKey)); EXPECT_EQ(PDFiumEngine::FocusElementType::kNone, GetFocusedElementType(engine.get())); } @@ -675,9 +759,9 @@ TEST_F(PDFiumEngineTabbingTest, TabbingWithModifiers) { EXPECT_EQ(-1, GetLastFocusedPage(engine.get())); // Tabbing with ctrl modifier. - ASSERT_FALSE(HandleTabEvent(engine.get(), PP_INPUTEVENT_MODIFIER_CONTROLKEY)); + ASSERT_FALSE(HandleTabEvent(engine.get(), kInputEventModifierControlKey)); // Tabbing with alt modifier. - ASSERT_FALSE(HandleTabEvent(engine.get(), PP_INPUTEVENT_MODIFIER_ALTKEY)); + ASSERT_FALSE(HandleTabEvent(engine.get(), kInputEventModifierAltKey)); // Tab to bring document into focus. ASSERT_TRUE(HandleTabEvent(engine.get(), 0)); @@ -685,9 +769,9 @@ TEST_F(PDFiumEngineTabbingTest, TabbingWithModifiers) { GetFocusedElementType(engine.get())); // Tabbing with ctrl modifier. - ASSERT_FALSE(HandleTabEvent(engine.get(), PP_INPUTEVENT_MODIFIER_CONTROLKEY)); + ASSERT_FALSE(HandleTabEvent(engine.get(), kInputEventModifierControlKey)); // Tabbing with alt modifier. - ASSERT_FALSE(HandleTabEvent(engine.get(), PP_INPUTEVENT_MODIFIER_ALTKEY)); + ASSERT_FALSE(HandleTabEvent(engine.get(), kInputEventModifierAltKey)); // Tab to bring first page into focus. ASSERT_TRUE(HandleTabEvent(engine.get(), 0)); @@ -695,9 +779,9 @@ TEST_F(PDFiumEngineTabbingTest, TabbingWithModifiers) { GetFocusedElementType(engine.get())); // Tabbing with ctrl modifier. - ASSERT_FALSE(HandleTabEvent(engine.get(), PP_INPUTEVENT_MODIFIER_CONTROLKEY)); + ASSERT_FALSE(HandleTabEvent(engine.get(), kInputEventModifierControlKey)); // Tabbing with alt modifier. - ASSERT_FALSE(HandleTabEvent(engine.get(), PP_INPUTEVENT_MODIFIER_ALTKEY)); + ASSERT_FALSE(HandleTabEvent(engine.get(), kInputEventModifierAltKey)); } TEST_F(PDFiumEngineTabbingTest, NoFocusableItemTabbingTest) { @@ -735,11 +819,11 @@ TEST_F(PDFiumEngineTabbingTest, NoFocusableItemTabbingTest) { GetFocusedElementType(engine.get())); // Tabbing backward. - ASSERT_TRUE(HandleTabEvent(engine.get(), PP_INPUTEVENT_MODIFIER_SHIFTKEY)); + ASSERT_TRUE(HandleTabEvent(engine.get(), kInputEventModifierShiftKey)); EXPECT_EQ(PDFiumEngine::FocusElementType::kDocument, GetFocusedElementType(engine.get())); - ASSERT_FALSE(HandleTabEvent(engine.get(), PP_INPUTEVENT_MODIFIER_SHIFTKEY)); + ASSERT_FALSE(HandleTabEvent(engine.get(), kInputEventModifierShiftKey)); EXPECT_EQ(PDFiumEngine::FocusElementType::kNone, GetFocusedElementType(engine.get())); } @@ -917,7 +1001,7 @@ TEST_F(PDFiumEngineTabbingTest, RetainSelectionOnFocusNotInFormTextArea) { EXPECT_EQ(1u, GetSelectionSize(engine.get())); // Tab to bring focus to a non form text area annotation (Button). - ASSERT_TRUE(HandleTabEvent(engine.get(), PP_INPUTEVENT_MODIFIER_SHIFTKEY)); + ASSERT_TRUE(HandleTabEvent(engine.get(), kInputEventModifierShiftKey)); EXPECT_EQ(PDFiumEngine::FocusElementType::kPage, GetFocusedElementType(engine.get())); EXPECT_EQ(0, GetLastFocusedPage(engine.get())); @@ -946,13 +1030,13 @@ TEST_F(PDFiumEngineTabbingTest, MaintainViewportWhenFocusIsUpdated) { { InSequence sequence; - static constexpr PP_Point kScrollValue = {510, 478}; - EXPECT_CALL(client, ScrollToY(kScrollValue.y, false)) + static constexpr gfx::Point kScrollValue = {510, 478}; + EXPECT_CALL(client, ScrollToY(kScrollValue.y(), false)) + .WillOnce(Invoke( + [&engine]() { engine->ScrolledToYPosition(kScrollValue.y()); })); + EXPECT_CALL(client, ScrollToX(kScrollValue.x())) .WillOnce(Invoke( - [&engine]() { engine->ScrolledToYPosition(kScrollValue.y); })); - EXPECT_CALL(client, ScrollToX(kScrollValue.x)).WillOnce(Invoke([&engine]() { - engine->ScrolledToXPosition(kScrollValue.x); - })); + [&engine]() { engine->ScrolledToXPosition(kScrollValue.x()); })); } EXPECT_EQ(PDFiumEngine::FocusElementType::kNone, @@ -970,9 +1054,9 @@ TEST_F(PDFiumEngineTabbingTest, MaintainViewportWhenFocusIsUpdated) { GetFocusedElementType(engine.get())); // Scroll focused annotation out of viewport. - static constexpr PP_Point kScrollPosition = {242, 746}; - engine->ScrolledToXPosition(kScrollPosition.x); - engine->ScrolledToYPosition(kScrollPosition.y); + static constexpr gfx::Point kScrollPosition = {242, 746}; + engine->ScrolledToXPosition(kScrollPosition.x()); + engine->ScrolledToYPosition(kScrollPosition.y()); engine->UpdateFocus(/*has_focus=*/false); EXPECT_EQ(PDFiumEngine::FocusElementType::kPage, @@ -999,16 +1083,16 @@ TEST_F(PDFiumEngineTabbingTest, ScrollFocusedAnnotationIntoView) { { InSequence sequence; - static constexpr PP_Point kScrollValues[] = {{510, 478}, {510, 478}}; + static constexpr gfx::Point kScrollValues[] = {{510, 478}, {510, 478}}; for (const auto& scroll_value : kScrollValues) { - EXPECT_CALL(client, ScrollToY(scroll_value.y, false)) + EXPECT_CALL(client, ScrollToY(scroll_value.y(), false)) .WillOnce(Invoke([&engine, &scroll_value]() { - engine->ScrolledToYPosition(scroll_value.y); + engine->ScrolledToYPosition(scroll_value.y()); })); - EXPECT_CALL(client, ScrollToX(scroll_value.x)) + EXPECT_CALL(client, ScrollToX(scroll_value.x())) .WillOnce(Invoke([&engine, &scroll_value]() { - engine->ScrolledToXPosition(scroll_value.x); + engine->ScrolledToXPosition(scroll_value.x()); })); } } @@ -1028,9 +1112,9 @@ TEST_F(PDFiumEngineTabbingTest, ScrollFocusedAnnotationIntoView) { GetFocusedElementType(engine.get())); // Scroll focused annotation out of viewport. - static constexpr PP_Point kScrollPosition = {242, 746}; - engine->ScrolledToXPosition(kScrollPosition.x); - engine->ScrolledToYPosition(kScrollPosition.y); + static constexpr gfx::Point kScrollPosition = {242, 746}; + engine->ScrolledToXPosition(kScrollPosition.x()); + engine->ScrolledToYPosition(kScrollPosition.y()); // Scroll the focused annotation into view. ScrollFocusedAnnotationIntoView(engine.get()); diff --git a/chromium/pdf/pdfium/pdfium_form_filler.cc b/chromium/pdf/pdfium/pdfium_form_filler.cc index 3cbf9e5910e..b6de6851ae0 100644 --- a/chromium/pdf/pdfium/pdfium_form_filler.cc +++ b/chromium/pdf/pdfium/pdfium_form_filler.cc @@ -12,9 +12,9 @@ #include "base/strings/string_number_conversions.h" #include "base/strings/utf_string_conversions.h" #include "pdf/pdfium/pdfium_engine.h" -#include "pdf/ppapi_migration/geometry_conversions.h" -#include "ppapi/cpp/rect.h" +#include "pdf/ppapi_migration/input_event_conversions.h" #include "third_party/pdfium/public/fpdf_annot.h" +#include "ui/gfx/geometry/rect.h" namespace chrome_pdf { @@ -28,8 +28,9 @@ std::string WideStringToString(FPDF_WIDESTRING wide_string) { } // namespace -PDFiumFormFiller::PDFiumFormFiller(PDFiumEngine* engine, bool enable_javascript) - : engine_(engine) { +PDFiumFormFiller::PDFiumFormFiller(PDFiumEngine* engine, + ScriptOption script_option) + : engine_(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 @@ -53,24 +54,6 @@ PDFiumFormFiller::PDFiumFormFiller(PDFiumEngine* engine, bool enable_javascript) FPDF_FORMFILLINFO::FFI_OnFocusChange = Form_OnFocusChange; FPDF_FORMFILLINFO::FFI_DoURIActionWithKeyboardModifier = Form_DoURIActionWithKeyboardModifier; -#if defined(PDF_ENABLE_XFA) - FPDF_FORMFILLINFO::xfa_disabled = false; - FPDF_FORMFILLINFO::FFI_EmailTo = Form_EmailTo; - FPDF_FORMFILLINFO::FFI_DisplayCaret = Form_DisplayCaret; - FPDF_FORMFILLINFO::FFI_SetCurrentPage = Form_SetCurrentPage; - FPDF_FORMFILLINFO::FFI_GetCurrentPageIndex = Form_GetCurrentPageIndex; - FPDF_FORMFILLINFO::FFI_GetPageViewRect = Form_GetPageViewRect; - FPDF_FORMFILLINFO::FFI_GetPlatform = Form_GetPlatform; - FPDF_FORMFILLINFO::FFI_PageEvent = Form_PageEvent; - FPDF_FORMFILLINFO::FFI_PopupMenu = Form_PopupMenu; - FPDF_FORMFILLINFO::FFI_PostRequestURL = Form_PostRequestURL; - FPDF_FORMFILLINFO::FFI_PutRequestURL = Form_PutRequestURL; - FPDF_FORMFILLINFO::FFI_UploadTo = Form_UploadTo; - FPDF_FORMFILLINFO::FFI_DownloadFromURL = Form_DownloadFromURL; - FPDF_FORMFILLINFO::FFI_OpenFile = Form_OpenFile; - FPDF_FORMFILLINFO::FFI_GotoURL = Form_GotoURL; - FPDF_FORMFILLINFO::FFI_GetLanguage = Form_GetLanguage; -#else FPDF_FORMFILLINFO::xfa_disabled = true; FPDF_FORMFILLINFO::FFI_EmailTo = nullptr; FPDF_FORMFILLINFO::FFI_DisplayCaret = nullptr; @@ -87,9 +70,10 @@ PDFiumFormFiller::PDFiumFormFiller(PDFiumEngine* engine, bool enable_javascript) FPDF_FORMFILLINFO::FFI_OpenFile = nullptr; FPDF_FORMFILLINFO::FFI_GotoURL = nullptr; FPDF_FORMFILLINFO::FFI_GetLanguage = nullptr; -#endif // defined(PDF_ENABLE_XFA) + FPDF_FORMFILLINFO::m_pJsPlatform = nullptr; - if (enable_javascript) { +#if defined(PDF_ENABLE_V8) + if (script_option != ScriptOption::kNoJavaScript) { FPDF_FORMFILLINFO::m_pJsPlatform = this; IPDF_JSPLATFORM::version = 3; IPDF_JSPLATFORM::app_alert = Form_Alert; @@ -101,9 +85,28 @@ PDFiumFormFiller::PDFiumFormFiller(PDFiumEngine* engine, bool enable_javascript) IPDF_JSPLATFORM::Doc_submitForm = Form_SubmitForm; IPDF_JSPLATFORM::Doc_gotoPage = Form_GotoPage; IPDF_JSPLATFORM::Field_browse = nullptr; - } else { - FPDF_FORMFILLINFO::m_pJsPlatform = nullptr; } +#if defined(PDF_ENABLE_XFA) + if (script_option == ScriptOption::kJavaScriptAndXFA) { + FPDF_FORMFILLINFO::xfa_disabled = false; + FPDF_FORMFILLINFO::FFI_EmailTo = Form_EmailTo; + FPDF_FORMFILLINFO::FFI_DisplayCaret = Form_DisplayCaret; + FPDF_FORMFILLINFO::FFI_SetCurrentPage = Form_SetCurrentPage; + FPDF_FORMFILLINFO::FFI_GetCurrentPageIndex = Form_GetCurrentPageIndex; + FPDF_FORMFILLINFO::FFI_GetPageViewRect = Form_GetPageViewRect; + FPDF_FORMFILLINFO::FFI_GetPlatform = Form_GetPlatform; + FPDF_FORMFILLINFO::FFI_PageEvent = Form_PageEvent; + FPDF_FORMFILLINFO::FFI_PopupMenu = Form_PopupMenu; + FPDF_FORMFILLINFO::FFI_PostRequestURL = Form_PostRequestURL; + FPDF_FORMFILLINFO::FFI_PutRequestURL = Form_PutRequestURL; + FPDF_FORMFILLINFO::FFI_UploadTo = Form_UploadTo; + FPDF_FORMFILLINFO::FFI_DownloadFromURL = Form_DownloadFromURL; + FPDF_FORMFILLINFO::FFI_OpenFile = Form_OpenFile; + FPDF_FORMFILLINFO::FFI_GotoURL = Form_GotoURL; + FPDF_FORMFILLINFO::FFI_GetLanguage = Form_GetLanguage; + } +#endif // defined(PDF_ENABLE_XFA) +#endif // defined(PDF_ENABLE_V8) } PDFiumFormFiller::~PDFiumFormFiller() = default; @@ -123,10 +126,9 @@ void PDFiumFormFiller::Form_Invalidate(FPDF_FORMFILLINFO* param, return; } - pp::Rect rect = engine->pages_[page_index]->PageToScreen( - PointFromPPPoint(engine->GetVisibleRect().point()), engine->current_zoom_, - left, top, right, bottom, - engine->layout_.options().default_page_orientation()); + gfx::Rect rect = engine->pages_[page_index]->PageToScreen( + engine->GetVisibleRect().origin(), engine->current_zoom_, left, top, + right, bottom, engine->layout_.options().default_page_orientation()); engine->client_->Invalidate(rect); } @@ -143,10 +145,9 @@ void PDFiumFormFiller::Form_OutputSelectedRect(FPDF_FORMFILLINFO* param, NOTREACHED(); return; } - pp::Rect rect = engine->pages_[page_index]->PageToScreen( - PointFromPPPoint(engine->GetVisibleRect().point()), engine->current_zoom_, - left, top, right, bottom, - engine->layout_.options().default_page_orientation()); + gfx::Rect rect = engine->pages_[page_index]->PageToScreen( + engine->GetVisibleRect().origin(), engine->current_zoom_, left, top, + right, bottom, engine->layout_.options().default_page_orientation()); if (rect.IsEmpty()) return; @@ -317,11 +318,11 @@ void PDFiumFormFiller::Form_DoURIActionWithKeyboardModifier( FPDF_BYTESTRING uri, int modifiers) { PDFiumEngine* engine = GetEngine(param); - bool middle_button = !!(modifiers & PP_INPUTEVENT_MODIFIER_MIDDLEBUTTONDOWN); - bool alt_key = !!(modifiers & PP_INPUTEVENT_MODIFIER_ALTKEY); - bool ctrl_key = !!(modifiers & PP_INPUTEVENT_MODIFIER_CONTROLKEY); - bool meta_key = !!(modifiers & PP_INPUTEVENT_MODIFIER_METAKEY); - bool shift_key = !!(modifiers & PP_INPUTEVENT_MODIFIER_SHIFTKEY); + bool middle_button = !!(modifiers & kInputEventModifierMiddleButtonDown); + bool alt_key = !!(modifiers & kInputEventModifierAltKey); + bool ctrl_key = !!(modifiers & kInputEventModifierControlKey); + bool meta_key = !!(modifiers & kInputEventModifierMetaKey); + bool shift_key = !!(modifiers & kInputEventModifierShiftKey); WindowOpenDisposition disposition = ui::DispositionFromClick( middle_button, alt_key, ctrl_key, meta_key, shift_key); @@ -329,6 +330,7 @@ void PDFiumFormFiller::Form_DoURIActionWithKeyboardModifier( engine->client_->NavigateTo(std::string(uri), disposition); } +#if defined(PDF_ENABLE_V8) #if defined(PDF_ENABLE_XFA) // static @@ -390,7 +392,7 @@ void PDFiumFormFiller::Form_GetPageViewRect(FPDF_FORMFILLINFO* param, return; } - pp::Rect page_view_rect = engine->GetPageContentsRect(page_index); + gfx::Rect page_view_rect = engine->GetPageContentsRect(page_index); float toolbar_height_in_screen_coords = engine->GetToolbarHeightInScreenCoords(); @@ -675,6 +677,8 @@ void PDFiumFormFiller::Form_GotoPage(IPDF_JSPLATFORM* param, int page_number) { engine->ScrollToPage(page_number); } +#endif // defined(PDF_ENABLE_V8) + // static PDFiumEngine* PDFiumFormFiller::GetEngine(FPDF_FORMFILLINFO* info) { auto* form_filler = static_cast<PDFiumFormFiller*>(info); diff --git a/chromium/pdf/pdfium/pdfium_form_filler.h b/chromium/pdf/pdfium/pdfium_form_filler.h index e362db83cbc..c787b497d1d 100644 --- a/chromium/pdf/pdfium/pdfium_form_filler.h +++ b/chromium/pdf/pdfium/pdfium_form_filler.h @@ -19,11 +19,16 @@ class PDFiumEngine; class PDFiumFormFiller : public FPDF_FORMFILLINFO, public IPDF_JSPLATFORM { public: - PDFiumFormFiller(PDFiumEngine* engine, bool enable_javascript); + enum class ScriptOption { kNoJavaScript, kJavaScript, kJavaScriptAndXFA }; + + // NOTE: |script_option| is ignored when PDF_ENABLE_V8 is not defined. + PDFiumFormFiller(PDFiumEngine* engine, ScriptOption script_option); PDFiumFormFiller(const PDFiumFormFiller&) = delete; PDFiumFormFiller& operator=(const PDFiumFormFiller&) = delete; ~PDFiumFormFiller(); + ScriptOption script_option() const { return script_option_; } + private: friend class FormFillerTest; @@ -72,6 +77,7 @@ class PDFiumFormFiller : public FPDF_FORMFILLINFO, public IPDF_JSPLATFORM { FPDF_BYTESTRING uri, int modifiers); +#if defined(PDF_ENABLE_V8) #if defined(PDF_ENABLE_XFA) static void Form_EmailTo(FPDF_FORMFILLINFO* param, FPDF_FILEHANDLER* file_handler, @@ -180,6 +186,7 @@ class PDFiumFormFiller : public FPDF_FORMFILLINFO, public IPDF_JSPLATFORM { int length, FPDF_WIDESTRING url); 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); @@ -188,7 +195,7 @@ class PDFiumFormFiller : public FPDF_FORMFILLINFO, public IPDF_JSPLATFORM { void KillTimer(int timer_id); PDFiumEngine* const engine_; - + 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 1fbfa63b5fe..ab5c48d3f9e 100644 --- a/chromium/pdf/pdfium/pdfium_form_filler_unittest.cc +++ b/chromium/pdf/pdfium/pdfium_form_filler_unittest.cc @@ -5,10 +5,11 @@ #include "build/build_config.h" #include "pdf/pdfium/pdfium_engine.h" #include "pdf/pdfium/pdfium_test_base.h" +#include "pdf/ppapi_migration/input_event_conversions.h" #include "pdf/test/test_client.h" -#include "ppapi/c/pp_point.h" #include "testing/gmock/include/gmock/gmock.h" #include "third_party/pdfium/public/fpdf_annot.h" +#include "ui/gfx/geometry/point.h" #include "ui/gfx/geometry/size.h" using testing::InSequence; @@ -89,38 +90,38 @@ TEST_F(FormFillerTest, DoURIActionWithKeyboardModifier) { } #if defined(OS_MAC) -#define modifier_key PP_INPUTEVENT_MODIFIER_METAKEY; +#define modifier_key kInputEventModifierMetaKey; #else -#define modifier_key PP_INPUTEVENT_MODIFIER_CONTROLKEY +#define modifier_key kInputEventModifierControlKey #endif int modifiers = 0; TriggerDoURIActionWithKeyboardModifier(engine.get(), kUri, modifiers); - modifiers = PP_INPUTEVENT_MODIFIER_ALTKEY; + modifiers = kInputEventModifierAltKey; TriggerDoURIActionWithKeyboardModifier(engine.get(), kUri, modifiers); modifiers = modifier_key; TriggerDoURIActionWithKeyboardModifier(engine.get(), kUri, modifiers); - modifiers = PP_INPUTEVENT_MODIFIER_SHIFTKEY; + modifiers = kInputEventModifierShiftKey; TriggerDoURIActionWithKeyboardModifier(engine.get(), kUri, modifiers); modifiers |= modifier_key; TriggerDoURIActionWithKeyboardModifier(engine.get(), kUri, modifiers); - modifiers = PP_INPUTEVENT_MODIFIER_MIDDLEBUTTONDOWN; + modifiers = kInputEventModifierMiddleButtonDown; TriggerDoURIActionWithKeyboardModifier(engine.get(), kUri, modifiers); - modifiers |= PP_INPUTEVENT_MODIFIER_SHIFTKEY; + modifiers |= kInputEventModifierShiftKey; TriggerDoURIActionWithKeyboardModifier(engine.get(), kUri, modifiers); } TEST_F(FormFillerTest, FormOnFocusChange) { struct { // Initial scroll position of the document. - PP_Point initial_position; + gfx::Point initial_position; // Page number on which the annotation is present. int page_index; // The index of test annotation on page_index. int annot_index; // The scroll position to bring the annotation into view. (0,0) if the // annotation is already in view. - PP_Point final_scroll_position; + gfx::Point final_scroll_position; } static constexpr test_cases[] = { {{0, 0}, 0, 0, {242, 746}}, {{0, 0}, 0, 1, {510, 478}}, {{242, 40}, 0, 0, {0, 746}}, {{60, 758}, 0, 0, {242, 0}}, @@ -138,19 +139,19 @@ TEST_F(FormFillerTest, FormOnFocusChange) { InSequence sequence; for (const auto& test_case : test_cases) { - if (test_case.final_scroll_position.y != 0) { + if (test_case.final_scroll_position.y() != 0) { EXPECT_CALL(client, - ScrollToY(test_case.final_scroll_position.y, false)); + ScrollToY(test_case.final_scroll_position.y(), false)); } - if (test_case.final_scroll_position.x != 0) - EXPECT_CALL(client, ScrollToX(test_case.final_scroll_position.x)); + if (test_case.final_scroll_position.x() != 0) + EXPECT_CALL(client, ScrollToX(test_case.final_scroll_position.x())); } } for (const auto& test_case : test_cases) { // Setting up the initial scroll positions. - engine->ScrolledToXPosition(test_case.initial_position.x); - engine->ScrolledToYPosition(test_case.initial_position.y); + engine->ScrolledToXPosition(test_case.initial_position.x()); + engine->ScrolledToYPosition(test_case.initial_position.y()); PDFiumPage& page = GetPDFiumPageForTest(*engine, test_case.page_index); ScopedFPDFAnnotation annot( diff --git a/chromium/pdf/pdfium/pdfium_page.cc b/chromium/pdf/pdfium/pdfium_page.cc index 66b9f6a4559..c5549b24ed0 100644 --- a/chromium/pdf/pdfium/pdfium_page.cc +++ b/chromium/pdf/pdfium/pdfium_page.cc @@ -11,6 +11,8 @@ #include <memory> #include <utility> +#include "base/bind.h" +#include "base/callback.h" #include "base/check_op.h" #include "base/metrics/histogram_functions.h" #include "base/notreached.h" @@ -23,14 +25,20 @@ #include "pdf/pdfium/pdfium_engine.h" #include "pdf/pdfium/pdfium_unsupported_features.h" #include "pdf/ppapi_migration/geometry_conversions.h" +#include "pdf/thumbnail.h" #include "ppapi/c/private/ppb_pdf.h" #include "printing/units.h" #include "third_party/pdfium/public/cpp/fpdf_scopers.h" #include "third_party/pdfium/public/fpdf_annot.h" #include "third_party/pdfium/public/fpdf_catalog.h" +#include "third_party/skia/include/core/SkBitmap.h" #include "ui/gfx/geometry/point.h" +#include "ui/gfx/geometry/point_f.h" #include "ui/gfx/geometry/rect.h" +#include "ui/gfx/geometry/rect_f.h" +#include "ui/gfx/geometry/size_f.h" #include "ui/gfx/geometry/vector2d.h" +#include "ui/gfx/geometry/vector2d_f.h" #include "ui/gfx/range/range.h" using printing::ConvertUnitDouble; @@ -58,10 +66,9 @@ bool IsValidLink(const std::string& url) { return pp::Var(url).is_string(); } -pp::FloatRect FloatPageRectToPixelRect(FPDF_PAGE page, - const pp::FloatRect& input) { - int output_width = FPDF_GetPageWidth(page); - int output_height = FPDF_GetPageHeight(page); +gfx::RectF FloatPageRectToPixelRect(FPDF_PAGE page, const gfx::RectF& input) { + int output_width = FPDF_GetPageWidthF(page); + int output_height = FPDF_GetPageHeightF(page); int min_x; int min_y; @@ -79,29 +86,38 @@ pp::FloatRect FloatPageRectToPixelRect(FPDF_PAGE page, if (max_y < min_y) std::swap(min_y, max_y); - pp::FloatRect output_rect( + // Make sure small but non-zero dimensions for |input| does not get rounded + // down to 0. + int width = max_x - min_x; + int height = max_y - min_y; + if (width == 0 && input.width()) + width = 1; + if (height == 0 && input.height()) + height = 1; + + gfx::RectF output_rect( ConvertUnitDouble(min_x, kPointsPerInch, kPixelsPerInch), ConvertUnitDouble(min_y, kPointsPerInch, kPixelsPerInch), - ConvertUnitDouble(max_x - min_x, kPointsPerInch, kPixelsPerInch), - ConvertUnitDouble(max_y - min_y, kPointsPerInch, kPixelsPerInch)); + ConvertUnitDouble(width, kPointsPerInch, kPixelsPerInch), + ConvertUnitDouble(height, kPointsPerInch, kPixelsPerInch)); return output_rect; } -pp::FloatRect GetFloatCharRectInPixels(FPDF_PAGE page, - FPDF_TEXTPAGE text_page, - int index) { +gfx::RectF GetFloatCharRectInPixels(FPDF_PAGE page, + FPDF_TEXTPAGE text_page, + int index) { double left; double right; double bottom; double top; if (!FPDFText_GetCharBox(text_page, index, &left, &right, &bottom, &top)) - return pp::FloatRect(); + return gfx::RectF(); if (right < left) std::swap(left, right); if (bottom < top) std::swap(top, bottom); - pp::FloatRect page_coords(left, top, right - left, bottom - top); + gfx::RectF page_coords(left, top, right - left, bottom - top); return FloatPageRectToPixelRect(page, page_coords); } @@ -145,14 +161,8 @@ PP_PrivateDirection GetDirectionFromAngle(float angle) { return PP_PRIVATEDIRECTION_BTT; } -float GetDistanceBetweenPoints(const pp::FloatPoint& p1, - const pp::FloatPoint& p2) { - pp::FloatPoint dist_vector = p1 - p2; - return sqrtf(powf(dist_vector.x(), 2) + powf(dist_vector.y(), 2)); -} - -void AddCharSizeToAverageCharSize(pp::FloatSize new_size, - pp::FloatSize* avg_size, +void AddCharSizeToAverageCharSize(gfx::SizeF new_size, + gfx::SizeF* avg_size, int* count) { // Some characters sometimes have a bogus empty bounding box. We don't want // them to impact the average. @@ -165,11 +175,11 @@ void AddCharSizeToAverageCharSize(pp::FloatSize new_size, } } -float GetRotatedCharWidth(float angle, const pp::FloatSize& size) { +float GetRotatedCharWidth(float angle, const gfx::SizeF& size) { return fabsf(cosf(angle) * size.width()) + fabsf(sinf(angle) * size.height()); } -float GetAngleOfVector(const pp::FloatPoint& v) { +float GetAngleOfVector(const gfx::Vector2dF& v) { float angle = atan2f(v.y(), v.x()); if (angle < 0) angle += k360DegreesInRadians; @@ -469,10 +479,10 @@ PDFiumPage::GetTextRunInfo(int start_char_index) { // If the first character in a text run is a space, we need to start // |text_run_bounds| from the space character instead of the first // non-space unicode character. - pp::FloatRect text_run_bounds = + gfx::RectF text_run_bounds = actual_start_char_index > start_char_index ? GetFloatCharRectInPixels(page, text_page, start_char_index) - : pp::FloatRect(); + : gfx::RectF(); // Pdfium trims more than 1 consecutive spaces to 1 space. DCHECK_LE(actual_start_char_index - start_char_index, 1); @@ -483,7 +493,7 @@ PDFiumPage::GetTextRunInfo(int start_char_index) { pp::PDF::PrivateAccessibilityTextRunInfo info; CalculateTextRunStyleInfo(char_index, &info.style); - pp::FloatRect start_char_rect = + gfx::RectF start_char_rect = GetFloatCharRectInPixels(page, text_page, char_index); float text_run_font_size = info.style.font_size; @@ -493,20 +503,19 @@ PDFiumPage::GetTextRunInfo(int start_char_index) { // lead to a break in the text run after only one space. Ex: ". Hello World" // would be split in two runs: "." and "Hello World". double font_size_minimum = FPDFText_GetFontSize(text_page, char_index) / 3.0; - pp::FloatSize avg_char_size = - pp::FloatSize(font_size_minimum, font_size_minimum); + gfx::SizeF avg_char_size(font_size_minimum, font_size_minimum); int non_whitespace_chars_count = 1; - AddCharSizeToAverageCharSize(start_char_rect.Floatsize(), &avg_char_size, + AddCharSizeToAverageCharSize(start_char_rect.size(), &avg_char_size, &non_whitespace_chars_count); // Add first non-space char to text run. - text_run_bounds = text_run_bounds.Union(start_char_rect); + text_run_bounds.Union(start_char_rect); PP_PrivateDirection char_direction = GetDirectionFromAngle(FPDFText_GetCharAngle(text_page, char_index)); if (char_index < chars_count) char_index++; - pp::FloatRect prev_char_rect = start_char_rect; + gfx::RectF prev_char_rect = start_char_rect; float estimated_font_size = std::max(start_char_rect.width(), start_char_rect.height()); @@ -530,7 +539,7 @@ PDFiumPage::GetTextRunInfo(int start_char_index) { break; unsigned int character = FPDFText_GetUnicode(text_page, char_index); - pp::FloatRect char_rect = + gfx::RectF char_rect = GetFloatCharRectInPixels(page, text_page, char_index); if (!base::IsUnicodeWhitespace(character)) { @@ -561,21 +570,20 @@ PDFiumPage::GetTextRunInfo(int start_char_index) { // Heuristic: End the text run if the center-point distance to the // previous character is less than 2.5x the average character size. - AddCharSizeToAverageCharSize(char_rect.Floatsize(), &avg_char_size, + AddCharSizeToAverageCharSize(char_rect.size(), &avg_char_size, &non_whitespace_chars_count); float avg_char_width = GetRotatedCharWidth(current_angle, avg_char_size); float distance = - GetDistanceBetweenPoints(char_rect.CenterPoint(), - prev_char_rect.CenterPoint()) - - GetRotatedCharWidth(current_angle, char_rect.Floatsize()) / 2 - - GetRotatedCharWidth(current_angle, prev_char_rect.Floatsize()) / 2; + (char_rect.CenterPoint() - prev_char_rect.CenterPoint()).Length() - + GetRotatedCharWidth(current_angle, char_rect.size()) / 2 - + GetRotatedCharWidth(current_angle, prev_char_rect.size()) / 2; if (distance > 2.5f * avg_char_width) break; - text_run_bounds = text_run_bounds.Union(char_rect); + text_run_bounds.Union(char_rect); prev_char_rect = char_rect; } @@ -598,7 +606,7 @@ PDFiumPage::GetTextRunInfo(int start_char_index) { info.len = char_index - start_char_index; info.style.font_size = text_run_font_size; - info.bounds = text_run_bounds; + info.bounds = PPFloatRectFromRectF(text_run_bounds); // Infer text direction from first and last character of the text run. We // can't base our decision on the character direction, since a character of a // RTL language will have an angle of 0 when not rotated, just like a @@ -614,7 +622,7 @@ uint32_t PDFiumPage::GetCharUnicode(int char_index) { return FPDFText_GetUnicode(text_page, char_index); } -pp::FloatRect PDFiumPage::GetCharBounds(int char_index) { +gfx::RectF PDFiumPage::GetCharBounds(int char_index) { FPDF_PAGE page = GetPage(); FPDF_TEXTPAGE text_page = GetTextPage(); return GetFloatCharRectInPixels(page, text_page, char_index); @@ -634,11 +642,11 @@ std::vector<PDFEngine::AccessibilityLinkInfo> PDFiumPage::GetLinkInfo() { cur_info.start_char_index = link.start_char_index; cur_info.char_count = link.char_count; - pp::Rect link_rect; + gfx::Rect link_rect; for (const auto& rect : link.bounding_rects) - link_rect = link_rect.Union(rect); - cur_info.bounds = pp::FloatRect(link_rect.x(), link_rect.y(), - link_rect.width(), link_rect.height()); + link_rect.Union(rect); + cur_info.bounds = gfx::RectF(link_rect.x(), link_rect.y(), + link_rect.width(), link_rect.height()); link_info.push_back(std::move(cur_info)); } @@ -656,9 +664,9 @@ std::vector<PDFEngine::AccessibilityImageInfo> PDFiumPage::GetImageInfo() { for (const Image& image : images_) { PDFEngine::AccessibilityImageInfo cur_info; cur_info.alt_text = image.alt_text; - cur_info.bounds = pp::FloatRect( - image.bounding_rect.x(), image.bounding_rect.y(), - image.bounding_rect.width(), image.bounding_rect.height()); + cur_info.bounds = + gfx::RectF(image.bounding_rect.x(), image.bounding_rect.y(), + image.bounding_rect.width(), image.bounding_rect.height()); image_info.push_back(std::move(cur_info)); } return image_info; @@ -677,7 +685,7 @@ PDFiumPage::GetHighlightInfo() { PDFEngine::AccessibilityHighlightInfo cur_info; cur_info.start_char_index = highlight.start_char_index; cur_info.char_count = highlight.char_count; - cur_info.bounds = pp::FloatRect( + cur_info.bounds = gfx::RectF( highlight.bounding_rect.x(), highlight.bounding_rect.y(), highlight.bounding_rect.width(), highlight.bounding_rect.height()); cur_info.color = highlight.color; @@ -703,7 +711,7 @@ PDFiumPage::GetTextFieldInfo() { cur_info.is_read_only = !!(text_field.flags & FPDF_FORMFLAG_READONLY); cur_info.is_required = !!(text_field.flags & FPDF_FORMFLAG_REQUIRED); cur_info.is_password = !!(text_field.flags & FPDF_FORMFLAG_TEXT_PASSWORD); - cur_info.bounds = pp::FloatRect( + cur_info.bounds = gfx::RectF( text_field.bounding_rect.x(), text_field.bounding_rect.y(), text_field.bounding_rect.width(), text_field.bounding_rect.height()); text_field_info.push_back(std::move(cur_info)); @@ -758,7 +766,7 @@ PDFiumPage::Area PDFiumPage::GetCharIndex(const gfx::Point& point, LinkTarget* target) { if (!available_) return NONSELECTABLE_AREA; - gfx::Point device_point = point - RectFromPPRect(rect_).OffsetFromOrigin(); + gfx::Point device_point = point - rect_.OffsetFromOrigin(); double new_x; double new_y; FPDF_BOOL ret = @@ -899,8 +907,8 @@ gfx::PointF PDFiumPage::TransformPageToScreenXY(const gfx::PointF& xy) { if (!available_) return gfx::PointF(); - pp::FloatRect page_rect(xy.x(), xy.y(), 0, 0); - pp::FloatRect pixel_rect(FloatPageRectToPixelRect(GetPage(), page_rect)); + gfx::RectF page_rect(xy.x(), xy.y(), 0, 0); + gfx::RectF pixel_rect(FloatPageRectToPixelRect(GetPage(), page_rect)); return gfx::PointF(pixel_rect.x(), pixel_rect.y()); } @@ -933,9 +941,9 @@ int PDFiumPage::GetLink(int char_index, LinkTarget* target) { return -1; } - pp::Point origin(PageToScreen(gfx::Point(), 1.0, left, top, right, bottom, - PageOrientation::kOriginal) - .point()); + gfx::Point origin = PageToScreen(gfx::Point(), 1.0, left, top, right, bottom, + PageOrientation::kOriginal) + .origin(); for (size_t i = 0; i < links_.size(); ++i) { for (const auto& rect : links_[i].bounding_rects) { if (rect.Contains(origin)) { @@ -1005,8 +1013,8 @@ void PDFiumPage::PopulateWebLinks() { double right; double bottom; FPDFLink_GetRect(links.get(), i, j, &left, &top, &right, &bottom); - pp::Rect rect = PageToScreen(gfx::Point(), 1.0, left, top, right, bottom, - PageOrientation::kOriginal); + gfx::Rect rect = PageToScreen(gfx::Point(), 1.0, left, top, right, bottom, + PageOrientation::kOriginal); if (rect.IsEmpty()) continue; link.bounding_rects.push_back(rect); @@ -1062,9 +1070,9 @@ void PDFiumPage::PopulateAnnotationLinks() { // Calculate underlying text range of link. GetUnderlyingTextRangeForRect( - pp::FloatRect(link_rect.left, link_rect.bottom, - std::abs(link_rect.right - link_rect.left), - std::abs(link_rect.bottom - link_rect.top)), + gfx::RectF(link_rect.left, link_rect.bottom, + std::abs(link_rect.right - link_rect.left), + std::abs(link_rect.bottom - link_rect.top)), &link.start_char_index, &link.char_count); links_.emplace_back(link); } @@ -1208,8 +1216,8 @@ void PDFiumPage::PopulateHighlight(FPDF_ANNOTATION annot) { PageToScreen(gfx::Point(), 1.0, rect.left, rect.top, rect.right, rect.bottom, PageOrientation::kOriginal); GetUnderlyingTextRangeForRect( - pp::FloatRect(rect.left, rect.bottom, std::abs(rect.right - rect.left), - std::abs(rect.bottom - rect.top)), + gfx::RectF(rect.left, rect.bottom, std::abs(rect.right - rect.left), + std::abs(rect.bottom - rect.top)), &highlight.start_char_index, &highlight.char_count); // Retrieve the color of the highlight. @@ -1355,7 +1363,7 @@ bool PDFiumPage::PopulateFormFieldProperties(FPDF_ANNOTATION annot, return true; } -bool PDFiumPage::GetUnderlyingTextRangeForRect(const pp::FloatRect& rect, +bool PDFiumPage::GetUnderlyingTextRangeForRect(const gfx::RectF& rect, int* start_index, int* char_len) { if (!available_) @@ -1400,15 +1408,15 @@ bool PDFiumPage::GetUnderlyingTextRangeForRect(const pp::FloatRect& rect, return true; } -pp::Rect PDFiumPage::PageToScreen(const gfx::Point& page_point, - double zoom, - double left, - double top, - double right, - double bottom, - PageOrientation orientation) const { +gfx::Rect PDFiumPage::PageToScreen(const gfx::Point& page_point, + double zoom, + double left, + double top, + double right, + double bottom, + PageOrientation orientation) const { if (!available_) - return pp::Rect(); + return gfx::Rect(); double start_x = (rect_.x() - page_point.x()) * zoom; double start_y = (rect_.y() - page_point.y()) * zoom; @@ -1418,7 +1426,7 @@ pp::Rect PDFiumPage::PageToScreen(const gfx::Point& page_point, !base::IsValueInRangeForNumericType<int>(start_y) || !base::IsValueInRangeForNumericType<int>(size_x) || !base::IsValueInRangeForNumericType<int>(size_y)) { - return pp::Rect(); + return gfx::Rect(); } int new_left; @@ -1451,10 +1459,67 @@ pp::Rect PDFiumPage::PageToScreen(const gfx::Point& page_point, new_size_y -= new_top; new_size_y += 1; if (!new_size_x.IsValid() || !new_size_y.IsValid()) - return pp::Rect(); + return gfx::Rect(); + + return gfx::Rect(new_left, new_top, new_size_x.ValueOrDie(), + new_size_y.ValueOrDie()); +} + +void PDFiumPage::RequestThumbnail(float device_pixel_ratio, + SendThumbnailCallback send_callback) { + DCHECK(!thumbnail_callback_); + + if (available()) { + GenerateAndSendThumbnail(device_pixel_ratio, std::move(send_callback)); + return; + } + + // It is safe to use base::Unretained(this) because the callback is only used + // by |this|. + thumbnail_callback_ = base::BindOnce( + &PDFiumPage::GenerateAndSendThumbnail, base::Unretained(this), + device_pixel_ratio, std::move(send_callback)); +} + +Thumbnail PDFiumPage::GenerateThumbnail(float device_pixel_ratio) { + DCHECK(available()); + + FPDF_PAGE page = GetPage(); + gfx::Size page_size(base::saturated_cast<int>(FPDF_GetPageWidthF(page)), + base::saturated_cast<int>(FPDF_GetPageHeightF(page))); + Thumbnail thumbnail(page_size, device_pixel_ratio); + + SkBitmap& sk_bitmap = thumbnail.bitmap(); + ScopedFPDFBitmap fpdf_bitmap(FPDFBitmap_CreateEx( + sk_bitmap.width(), sk_bitmap.height(), FPDFBitmap_BGRA, + sk_bitmap.getPixels(), sk_bitmap.rowBytes())); + + // Clear the bitmap. + FPDFBitmap_FillRect(fpdf_bitmap.get(), /*left=*/0, /*top=*/0, + sk_bitmap.width(), sk_bitmap.height(), + /*color=*/0xFFFFFFFF); + + // The combination of the |FPDF_REVERSE_BYTE_ORDER| rendering flag and the + // |FPDFBitmap_BGRA| format when initializing |fpdf_bitmap| results in an RGBA + // rendering, which is the format required by HTML <canvas>. + FPDF_RenderPageBitmap(fpdf_bitmap.get(), GetPage(), /*start_x=*/0, + /*start_y=*/0, sk_bitmap.width(), sk_bitmap.height(), + /*rotate=*/0, FPDF_ANNOT | FPDF_REVERSE_BYTE_ORDER); + + return thumbnail; +} + +void PDFiumPage::GenerateAndSendThumbnail(float device_pixel_ratio, + SendThumbnailCallback send_callback) { + std::move(send_callback).Run(GenerateThumbnail(device_pixel_ratio)); +} + +void PDFiumPage::MarkAvailable() { + available_ = true; - return pp::Rect(new_left, new_top, new_size_x.ValueOrDie(), - new_size_y.ValueOrDie()); + // Fulfill pending thumbnail request. + if (thumbnail_callback_) + std::move(thumbnail_callback_).Run(); } PDFiumPage::ScopedUnloadPreventer::ScopedUnloadPreventer(PDFiumPage* page) diff --git a/chromium/pdf/pdfium/pdfium_page.h b/chromium/pdf/pdfium/pdfium_page.h index a8a0167d458..ce29a0b5835 100644 --- a/chromium/pdf/pdfium/pdfium_page.h +++ b/chromium/pdf/pdfium/pdfium_page.h @@ -10,26 +10,30 @@ #include <string> #include <vector> +#include "base/callback.h" +#include "base/callback_forward.h" #include "base/gtest_prod_util.h" #include "base/optional.h" #include "base/strings/string16.h" #include "pdf/page_orientation.h" #include "pdf/pdf_engine.h" #include "ppapi/cpp/private/pdf.h" -#include "ppapi/cpp/rect.h" #include "third_party/pdfium/public/cpp/fpdf_scopers.h" #include "third_party/pdfium/public/fpdf_doc.h" #include "third_party/pdfium/public/fpdf_formfill.h" #include "third_party/pdfium/public/fpdf_text.h" #include "ui/gfx/geometry/point_f.h" +#include "ui/gfx/geometry/rect.h" namespace gfx { class Point; +class RectF; } // namespace gfx namespace chrome_pdf { class PDFiumEngine; +class Thumbnail; // Wrapper around a page from the document. class PDFiumPage { @@ -59,7 +63,7 @@ class PDFiumPage { // Get a unicode character from the page. uint32_t GetCharUnicode(int char_index); // Get the bounds of a character in page pixels. - pp::FloatRect GetCharBounds(int char_index); + gfx::RectF GetCharBounds(int char_index); // For all the links on the page, get their urls, underlying text ranges and // bounding boxes. std::vector<PDFEngine::AccessibilityLinkInfo> GetLinkInfo(); @@ -144,28 +148,35 @@ class PDFiumPage { // Given a rectangle in page coordinates, computes the range of continuous // characters which lie inside that rectangle. Returns false without // modifying the out parameters if no character lies inside the rectangle. - bool GetUnderlyingTextRangeForRect(const pp::FloatRect& rect, + bool GetUnderlyingTextRangeForRect(const gfx::RectF& rect, int* start_index, int* char_len); // Converts from page coordinates to screen coordinates. - pp::Rect PageToScreen(const gfx::Point& page_point, - double zoom, - double left, - double top, - double right, - double bottom, - PageOrientation orientation) const; + gfx::Rect PageToScreen(const gfx::Point& page_point, + double zoom, + double left, + double top, + double right, + double bottom, + PageOrientation orientation) const; + + // Sets the callbacks for sending the thumbnail. + void RequestThumbnail(float device_pixel_ratio, + SendThumbnailCallback send_callback); + + // Generates a page thumbnail accommodating a specific |device_pixel_ratio|. + Thumbnail GenerateThumbnail(float device_pixel_ratio); int index() const { return index_; } - const pp::Rect& rect() const { return rect_; } - void set_rect(const pp::Rect& r) { rect_ = r; } + const gfx::Rect& rect() const { return rect_; } + void set_rect(const gfx::Rect& r) { rect_ = r; } // Availability is a one-way transition: A page can become available, but it // cannot become unavailable (unless deleted entirely). bool available() const { return available_; } - void MarkAvailable() { available_ = true; } + void MarkAvailable(); void set_calculated_links(bool calculated_links) { calculated_links_ = calculated_links; @@ -208,7 +219,7 @@ class PDFiumPage { int32_t start_char_index = -1; // Represents the number of characters that the link overlaps with. int32_t char_count = 0; - std::vector<pp::Rect> bounding_rects; + std::vector<gfx::Rect> bounding_rects; LinkTarget target; }; @@ -218,7 +229,7 @@ class PDFiumPage { Image(const Image& other); ~Image(); - pp::Rect bounding_rect; + gfx::Rect bounding_rect; // Alt text is available only for tagged PDFs. std::string alt_text; }; @@ -233,7 +244,7 @@ class PDFiumPage { int32_t start_char_index = -1; // Number of characters encompassed by this highlight. int32_t char_count = 0; - pp::Rect bounding_rect; + gfx::Rect bounding_rect; // Color of the highlight in ARGB. Alpha is stored in the first 8 MSBs. RGB // follows after it with each using 8 bytes. @@ -249,7 +260,7 @@ class PDFiumPage { FormField(const FormField& other); ~FormField(); - pp::Rect bounding_rect; + gfx::Rect bounding_rect; // Represents the name of form field as defined in the field dictionary. std::string name; // Represents the flags of form field as defined in the field dictionary. @@ -371,13 +382,16 @@ class PDFiumPage { const std::vector<Highlight>& highlights); bool PopulateFormFieldProperties(FPDF_ANNOTATION annot, FormField* form_field); + // Generates and sends the thumbnail using |send_callback|. + void GenerateAndSendThumbnail(float device_pixel_ratio, + SendThumbnailCallback send_callback); PDFiumEngine* engine_; ScopedFPDFPage page_; ScopedFPDFTextPage text_page_; int index_; int preventing_unload_count_ = 0; - pp::Rect rect_; + gfx::Rect rect_; bool calculated_links_ = false; std::vector<Link> links_; bool calculated_images_ = false; @@ -392,6 +406,7 @@ class PDFiumPage { // The set of character indices on which text runs need to be broken for page // objects. std::set<int> page_object_text_run_breaks_; + base::OnceClosure thumbnail_callback_; bool available_; }; diff --git a/chromium/pdf/pdfium/pdfium_page_unittest.cc b/chromium/pdf/pdfium/pdfium_page_unittest.cc index 5cecc5b711b..c70e14efc25 100644 --- a/chromium/pdf/pdfium/pdfium_page_unittest.cc +++ b/chromium/pdf/pdfium/pdfium_page_unittest.cc @@ -8,16 +8,25 @@ #include <vector> #include "base/check.h" +#include "base/files/file_path.h" #include "base/optional.h" +#include "base/path_service.h" #include "base/strings/string_util.h" +#include "base/strings/stringprintf.h" #include "base/test/gtest_util.h" +#include "cc/test/pixel_comparator.h" +#include "cc/test/pixel_test_utils.h" #include "pdf/pdfium/pdfium_engine.h" #include "pdf/pdfium/pdfium_test_base.h" +#include "pdf/ppapi_migration/geometry_conversions.h" #include "pdf/test/test_client.h" -#include "pdf/test/test_utils.h" +#include "pdf/thumbnail.h" #include "ppapi/c/private/ppb_pdf.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/pdfium/public/fpdf_formfill.h" +#include "third_party/skia/include/core/SkBitmap.h" +#include "ui/gfx/geometry/rect.h" +#include "ui/gfx/geometry/rect_f.h" #include "ui/gfx/range/range.h" namespace chrome_pdf { @@ -40,11 +49,27 @@ TEST(PDFiumPageHelperDeathTest, ToPDFiumRotation) { #endif } +// Clone of pp::PDF::PrivateAccessibilityTextRunInfo. +struct ExpectedAccessibilityTextRunInfo { + uint32_t len; + gfx::RectF bounds; + PP_PrivateDirection direction; + pp::PDF::PrivateAccessibilityTextStyleInfo style; +}; + void CompareTextRuns( - const pp::PDF::PrivateAccessibilityTextRunInfo& expected_text_run, - const pp::PDF::PrivateAccessibilityTextRunInfo actual_text_run) { + const ExpectedAccessibilityTextRunInfo& expected_text_run, + const pp::PDF::PrivateAccessibilityTextRunInfo& actual_text_run) { EXPECT_EQ(expected_text_run.len, actual_text_run.len); - CompareRect(expected_text_run.bounds, actual_text_run.bounds); + + // Use EXPECT_FLOAT_EQ() here instead of direct gfx::RectF comparisons to + // avoid having to deal with float rounding errors. + gfx::RectF actual_bounds = RectFFromPPFloatRect(actual_text_run.bounds); + EXPECT_FLOAT_EQ(expected_text_run.bounds.x(), actual_bounds.x()); + EXPECT_FLOAT_EQ(expected_text_run.bounds.y(), actual_bounds.y()); + EXPECT_FLOAT_EQ(expected_text_run.bounds.width(), actual_bounds.width()); + EXPECT_FLOAT_EQ(expected_text_run.bounds.height(), actual_bounds.height()); + EXPECT_EQ(expected_text_run.direction, actual_text_run.direction); const pp::PDF::PrivateAccessibilityTextStyleInfo& expected_style = @@ -72,6 +97,23 @@ void PopulateTextObjects(const std::vector<gfx::Range>& ranges, } } +base::FilePath GetThumbnailTestData(const std::string& expectation_file_prefix, + size_t page_index, + float device_pixel_ratio) { + std::string file_dir = base::StringPrintf("%.1fx", device_pixel_ratio); + std::string file_name = base::StringPrintf( + "%s_expected.pdf.%zu.png", expectation_file_prefix.c_str(), page_index); + base::FilePath root_path; + if (!base::PathService::Get(base::DIR_SOURCE_ROOT, &root_path)) + return base::FilePath(); + return root_path.Append(FILE_PATH_LITERAL("pdf")) + .Append(FILE_PATH_LITERAL("test")) + .Append(FILE_PATH_LITERAL("data")) + .Append(FILE_PATH_LITERAL("thumbnail")) + .AppendASCII(file_dir) + .AppendASCII(file_name); +} + } // namespace using PDFiumPageTest = PDFiumTestBase; @@ -116,9 +158,9 @@ TEST_F(PDFiumPageLinkTest, TestLinkGeneration) { EXPECT_EQ(16, link.char_count); ASSERT_EQ(1u, link.bounding_rects.size()); if (is_chromeos) { - CompareRect({75, 192, 110, 15}, link.bounding_rects[0]); + EXPECT_EQ(gfx::Rect(75, 192, 110, 15), link.bounding_rects[0]); } else { - CompareRect({75, 191, 110, 16}, link.bounding_rects[0]); + EXPECT_EQ(gfx::Rect(75, 191, 110, 16), link.bounding_rects[0]); } const PDFiumPage::Link& second_link = links[1]; @@ -127,9 +169,9 @@ TEST_F(PDFiumPageLinkTest, TestLinkGeneration) { EXPECT_EQ(15, second_link.char_count); ASSERT_EQ(1u, second_link.bounding_rects.size()); if (is_chromeos) { - CompareRect({131, 120, 138, 22}, second_link.bounding_rects[0]); + EXPECT_EQ(gfx::Rect(131, 120, 138, 22), second_link.bounding_rects[0]); } else { - CompareRect({131, 121, 138, 20}, second_link.bounding_rects[0]); + EXPECT_EQ(gfx::Rect(131, 121, 138, 20), second_link.bounding_rects[0]); } const PDFiumPage::Link& third_link = links[2]; @@ -137,14 +179,14 @@ TEST_F(PDFiumPageLinkTest, TestLinkGeneration) { EXPECT_EQ(92, third_link.start_char_index); EXPECT_EQ(17, third_link.char_count); ASSERT_EQ(1u, third_link.bounding_rects.size()); - CompareRect({82, 67, 161, 21}, third_link.bounding_rects[0]); + EXPECT_EQ(gfx::Rect(82, 67, 161, 21), third_link.bounding_rects[0]); } TEST_F(PDFiumPageLinkTest, TestAnnotLinkGeneration) { struct ExpectedLink { int32_t start_char_index; int32_t char_count; - std::vector<pp::Rect> bounding_rects; + std::vector<gfx::Rect> bounding_rects; std::string url; int page; float y_in_pixels; @@ -181,8 +223,8 @@ TEST_F(PDFiumPageLinkTest, TestAnnotLinkGeneration) { size_t bounds_size = actual_current_link.bounding_rects.size(); ASSERT_EQ(expected_current_link.bounding_rects.size(), bounds_size); for (size_t bounds_index = 0; bounds_index < bounds_size; ++bounds_index) { - CompareRect(expected_current_link.bounding_rects[bounds_index], - actual_current_link.bounding_rects[bounds_index]); + EXPECT_EQ(expected_current_link.bounding_rects[bounds_index], + actual_current_link.bounding_rects[bounds_index]); } EXPECT_EQ(expected_current_link.url, actual_current_link.target.url); if (actual_current_link.target.url.empty()) { @@ -206,11 +248,11 @@ TEST_F(PDFiumPageImageTest, TestCalculateImages) { PDFiumPage& page = GetPDFiumPageForTest(*engine, 0); page.CalculateImages(); ASSERT_EQ(3u, page.images_.size()); - CompareRect({380, 78, 67, 68}, page.images_[0].bounding_rect); + EXPECT_EQ(gfx::Rect(380, 78, 67, 68), page.images_[0].bounding_rect); EXPECT_EQ("Image 1", page.images_[0].alt_text); - CompareRect({380, 385, 27, 28}, page.images_[1].bounding_rect); + EXPECT_EQ(gfx::Rect(380, 385, 27, 28), page.images_[1].bounding_rect); EXPECT_EQ("Image 2", page.images_[1].alt_text); - CompareRect({380, 678, 1, 1}, page.images_[2].bounding_rect); + EXPECT_EQ(gfx::Rect(380, 678, 1, 1), page.images_[2].bounding_rect); EXPECT_EQ("Image 3", page.images_[2].alt_text); } @@ -224,11 +266,11 @@ TEST_F(PDFiumPageImageTest, TestImageAltText) { PDFiumPage& page = GetPDFiumPageForTest(*engine, 0); page.CalculateImages(); ASSERT_EQ(3u, page.images_.size()); - CompareRect({380, 78, 67, 68}, page.images_[0].bounding_rect); + EXPECT_EQ(gfx::Rect(380, 78, 67, 68), page.images_[0].bounding_rect); EXPECT_EQ("Image 1", page.images_[0].alt_text); - CompareRect({380, 385, 27, 28}, page.images_[1].bounding_rect); + EXPECT_EQ(gfx::Rect(380, 385, 27, 28), page.images_[1].bounding_rect); EXPECT_EQ("", page.images_[1].alt_text); - CompareRect({380, 678, 1, 1}, page.images_[2].bounding_rect); + EXPECT_EQ(gfx::Rect(380, 678, 1, 1), page.images_[2].bounding_rect); EXPECT_EQ("", page.images_[2].alt_text); } @@ -252,7 +294,7 @@ TEST_F(PDFiumPageTextTest, TestTextRunBounds) { EXPECT_TRUE(base::IsUnicodeWhitespace( engine->GetCharUnicode(kPageIndex, kFirstRunStartIndex))); - pp::FloatRect text_run_bounds = actual_text_run_1.bounds; + gfx::RectF text_run_bounds = RectFFromPPFloatRect(actual_text_run_1.bounds); EXPECT_TRUE(text_run_bounds.Contains( engine->GetCharBounds(kPageIndex, kFirstRunStartIndex))); @@ -270,7 +312,7 @@ TEST_F(PDFiumPageTextTest, TestTextRunBounds) { EXPECT_TRUE(base::IsUnicodeWhitespace( engine->GetCharUnicode(kPageIndex, kFirstRunEndIndex))); - pp::FloatRect end_char_rect = + gfx::RectF end_char_rect = engine->GetCharBounds(kPageIndex, kFirstRunEndIndex); EXPECT_FALSE(text_run_bounds.Contains(end_char_rect)); // Equals to the length of the previous text run. @@ -288,7 +330,7 @@ TEST_F(PDFiumPageTextTest, TestTextRunBounds) { EXPECT_FALSE(base::IsUnicodeWhitespace( engine->GetCharUnicode(kPageIndex, kSecondRunStartIndex))); - text_run_bounds = actual_text_run_2.bounds; + text_run_bounds = RectFFromPPFloatRect(actual_text_run_2.bounds); EXPECT_TRUE(text_run_bounds.Contains( engine->GetCharBounds(kPageIndex, kSecondRunStartIndex))); @@ -331,37 +373,31 @@ TEST_F(PDFiumPageTextTest, GetTextRunInfo) { // The links span from [7, 22], [52, 66] and [92, 108] with 16, 15 and 17 // text run lengths respectively. There are text runs preceding and // succeeding them. - pp::PDF::PrivateAccessibilityTextRunInfo expected_text_runs[] = { - {7, - PP_MakeFloatRectFromXYWH(26.666666f, 189.333333f, 38.666672f, - 13.333344f), + ExpectedAccessibilityTextRunInfo expected_text_runs[] = { + {7, gfx::RectF(26.666666f, 189.333333f, 38.666672f, 13.333344f), PP_PrivateDirection::PP_PRIVATEDIRECTION_LTR, expected_style_1}, - {16, - PP_MakeFloatRectFromXYWH(70.666664f, 189.333333f, 108.0f, 14.666672f), + {16, gfx::RectF(70.666664f, 189.333333f, 108.0f, 14.666672f), PP_PrivateDirection::PP_PRIVATEDIRECTION_LTR, expected_style_1}, - {20, - PP_MakeFloatRectFromXYWH(181.333333f, 189.333333f, 117.333333f, - 14.666672f), + {20, gfx::RectF(181.333333f, 189.333333f, 117.333333f, 14.666672f), PP_PrivateDirection::PP_PRIVATEDIRECTION_LTR, expected_style_1}, - {9, PP_MakeFloatRectFromXYWH(28.0f, 117.33334f, 89.333328f, 20.0f), + {9, gfx::RectF(28.0f, 117.33334f, 89.333328f, 20.0f), PP_PrivateDirection::PP_PRIVATEDIRECTION_LTR, expected_style_2}, - {15, PP_MakeFloatRectFromXYWH(126.66666f, 117.33334f, 137.33334f, 20.0f), + {15, gfx::RectF(126.66666f, 117.33334f, 137.33334f, 20.0f), PP_PrivateDirection::PP_PRIVATEDIRECTION_LTR, expected_style_2}, - {20, - PP_MakeFloatRectFromXYWH(266.66666f, 118.66666f, 169.33334f, 18.666664f), + {20, gfx::RectF(266.66666f, 118.66666f, 169.33334f, 18.666664f), PP_PrivateDirection::PP_PRIVATEDIRECTION_LTR, expected_style_2}, - {5, PP_MakeFloatRectFromXYWH(28.0f, 65.333336f, 40.0f, 18.666664f), + {5, gfx::RectF(28.0f, 65.333336f, 40.0f, 18.666664f), PP_PrivateDirection::PP_PRIVATEDIRECTION_LTR, expected_style_2}, - {17, PP_MakeFloatRectFromXYWH(77.333336f, 64.0f, 160.0f, 20.0f), + {17, gfx::RectF(77.333336f, 64.0f, 160.0f, 20.0f), PP_PrivateDirection::PP_PRIVATEDIRECTION_LTR, expected_style_2}}; if (IsRunningOnChromeOS()) { expected_text_runs[4].bounds = - PP_MakeFloatRectFromXYWH(126.66666f, 117.33334f, 137.33334f, 21.33334f); + gfx::RectF(126.66666f, 117.33334f, 137.33334f, 21.33334f); expected_text_runs[5].bounds = - PP_MakeFloatRectFromXYWH(266.66666f, 118.66666f, 170.66666f, 20.0f); + gfx::RectF(266.66666f, 118.66666f, 170.66666f, 20.0f); expected_text_runs[7].bounds = - PP_MakeFloatRectFromXYWH(77.333336f, 64.0f, 160.0f, 21.33333f); + gfx::RectF(77.333336f, 64.0f, 160.0f, 21.33333f); } // Test negative char index returns nullopt @@ -397,27 +433,23 @@ TEST_F(PDFiumPageTextTest, TestHighlightTextRunInfo) { static const pp::PDF::PrivateAccessibilityTextStyleInfo kExpectedStyle = { "Helvetica", 0, PP_TEXTRENDERINGMODE_FILL, 16, 0xff000000, 0xff000000, false, false}; - pp::PDF::PrivateAccessibilityTextRunInfo expected_text_runs[] = { - {5, - PP_MakeFloatRectFromXYWH(1.3333334f, 198.66667f, 46.666668f, 14.666672f), + ExpectedAccessibilityTextRunInfo expected_text_runs[] = { + {5, gfx::RectF(1.3333334f, 198.66667f, 46.666668f, 14.666672f), PP_PrivateDirection::PP_PRIVATEDIRECTION_LTR, kExpectedStyle}, - {7, - PP_MakeFloatRectFromXYWH(50.666668f, 198.66667f, 47.999996f, 17.333328f), + {7, gfx::RectF(50.666668f, 198.66667f, 47.999996f, 17.333328f), PP_PrivateDirection::PP_PRIVATEDIRECTION_LTR, kExpectedStyle}, - {7, - PP_MakeFloatRectFromXYWH(106.66666f, 198.66667f, 73.333336f, 18.666672f), + {7, gfx::RectF(106.66666f, 198.66667f, 73.333336f, 18.666672f), PP_PrivateDirection::PP_PRIVATEDIRECTION_LTR, kExpectedStyle}, - {2, PP_MakeFloatRectFromXYWH(181.33333f, 192.0f, 16.0f, 25.333344f), + {2, gfx::RectF(181.33333f, 202.66667f, 16.0f, 14.66667f), PP_PrivateDirection::PP_PRIVATEDIRECTION_NONE, kExpectedStyle}, - {2, - PP_MakeFloatRectFromXYWH(198.66667f, 202.66667f, 21.333328f, 10.666672f), + {2, gfx::RectF(198.66667f, 202.66667f, 21.333328f, 10.666672f), PP_PrivateDirection::PP_PRIVATEDIRECTION_LTR, kExpectedStyle}}; if (IsRunningOnChromeOS()) { - expected_text_runs[2].bounds = PP_MakeFloatRectFromXYWH( - 106.66666f, 198.66667f, 73.333336f, 19.999985f); - expected_text_runs[4].bounds = PP_MakeFloatRectFromXYWH( - 198.66667f, 201.33333f, 21.333328f, 12.000015f); + expected_text_runs[2].bounds = + gfx::RectF(106.66666f, 198.66667f, 73.333336f, 19.999985f); + expected_text_runs[4].bounds = + gfx::RectF(198.66667f, 201.33333f, 21.333328f, 12.000015f); } int current_char_index = 0; @@ -437,7 +469,7 @@ TEST_F(PDFiumPageHighlightTest, TestPopulateHighlights) { struct ExpectedHighlight { int32_t start_char_index; int32_t char_count; - pp::Rect bounding_rect; + gfx::Rect bounding_rect; uint32_t color; }; @@ -464,8 +496,8 @@ TEST_F(PDFiumPageHighlightTest, TestPopulateHighlights) { page.highlights_[i].start_char_index); ASSERT_EQ(kExpectedHighlights[i].char_count, page.highlights_[i].char_count); - CompareRect(kExpectedHighlights[i].bounding_rect, - page.highlights_[i].bounding_rect); + EXPECT_EQ(kExpectedHighlights[i].bounding_rect, + page.highlights_[i].bounding_rect); ASSERT_EQ(kExpectedHighlights[i].color, page.highlights_[i].color); } } @@ -476,7 +508,7 @@ TEST_F(PDFiumPageTextFieldTest, TestPopulateTextFields) { struct ExpectedTextField { const char* name; const char* value; - pp::Rect bounding_rect; + gfx::Rect bounding_rect; int flags; }; @@ -500,8 +532,8 @@ TEST_F(PDFiumPageTextFieldTest, TestPopulateTextFields) { for (size_t i = 0; i < text_fields_count; ++i) { EXPECT_EQ(kExpectedTextFields[i].name, page.text_fields_[i].name); EXPECT_EQ(kExpectedTextFields[i].value, page.text_fields_[i].value); - CompareRect(kExpectedTextFields[i].bounding_rect, - page.text_fields_[i].bounding_rect); + EXPECT_EQ(kExpectedTextFields[i].bounding_rect, + page.text_fields_[i].bounding_rect); EXPECT_EQ(kExpectedTextFields[i].flags, page.text_fields_[i].flags); } } @@ -517,7 +549,7 @@ TEST_F(PDFiumPageChoiceFieldTest, TestPopulateChoiceFields) { struct ExpectedChoiceField { const char* name; std::vector<struct ExpectedChoiceFieldOption> options; - pp::Rect bounding_rect; + gfx::Rect bounding_rect; int flags; }; @@ -587,8 +619,8 @@ TEST_F(PDFiumPageChoiceFieldTest, TestPopulateChoiceFields) { EXPECT_EQ(kExpectedChoiceFields[i].options[j].is_selected, page.choice_fields_[i].options[j].is_selected); } - CompareRect(kExpectedChoiceFields[i].bounding_rect, - page.choice_fields_[i].bounding_rect); + EXPECT_EQ(kExpectedChoiceFields[i].bounding_rect, + page.choice_fields_[i].bounding_rect); EXPECT_EQ(kExpectedChoiceFields[i].flags, page.choice_fields_[i].flags); } } @@ -604,7 +636,7 @@ TEST_F(PDFiumPageButtonTest, TestPopulateButtons) { bool is_checked; uint32_t control_count; int control_index; - pp::Rect bounding_rect; + gfx::Rect bounding_rect; }; static const ExpectedButton kExpectedButtons[] = {{"readOnlyCheckbox", @@ -669,8 +701,8 @@ TEST_F(PDFiumPageButtonTest, TestPopulateButtons) { page.buttons_[i].control_count); EXPECT_EQ(kExpectedButtons[i].control_index, page.buttons_[i].control_index); - CompareRect(kExpectedButtons[i].bounding_rect, - page.buttons_[i].bounding_rect); + EXPECT_EQ(kExpectedButtons[i].bounding_rect, + page.buttons_[i].bounding_rect); } } @@ -705,4 +737,64 @@ TEST_F(PDFiumPageOverlappingTest, CountCompleteOverlaps) { ASSERT_EQ(12u, PDFiumPage::CountLinkHighlightOverlaps(links, highlights)); } +class PDFiumPageThumbnailTest : public PDFiumTestBase { + public: + PDFiumPageThumbnailTest() = default; + PDFiumPageThumbnailTest(const PDFiumPageThumbnailTest&) = delete; + PDFiumPageThumbnailTest& operator=(const PDFiumPageThumbnailTest&) = delete; + ~PDFiumPageThumbnailTest() override = default; + + void TestGenerateThumbnail(PDFiumEngine& engine, + size_t page_index, + float device_pixel_ratio, + const gfx::Size& expected_thumbnail_size, + const std::string& expectation_file_prefix) { + PDFiumPage& page = GetPDFiumPageForTest(engine, page_index); + Thumbnail thumbnail = page.GenerateThumbnail(device_pixel_ratio); + EXPECT_EQ(expected_thumbnail_size, gfx::Size(thumbnail.bitmap().width(), + thumbnail.bitmap().height())); + EXPECT_EQ(device_pixel_ratio, thumbnail.device_pixel_ratio()); + + base::FilePath expectation_png_file_path = GetThumbnailTestData( + expectation_file_prefix, page_index, device_pixel_ratio); + + cc::MatchesPNGFile(thumbnail.bitmap(), expectation_png_file_path, + cc::ExactPixelComparator(/*discard_alpha=*/false)); + } +}; + +TEST_F(PDFiumPageThumbnailTest, GenerateThumbnail) { + TestClient client; + std::unique_ptr<PDFiumEngine> engine = + InitializeEngine(&client, FILE_PATH_LITERAL("variable_page_sizes.pdf")); + ASSERT_EQ(7, engine->GetNumberOfPages()); + + static constexpr struct { + size_t page_index; + float device_pixel_ratio; + gfx::Size expected_thumbnail_size; + } kGenerateThumbnailTestParams[] = { + {0, 1, {108, 140}}, // ANSI Letter + {1, 1, {108, 152}}, // ISO 216 A4 + {2, 1, {140, 140}}, // Square + {3, 1, {540, 108}}, // Wide + {4, 1, {108, 540}}, // Tall + {5, 1, {1399, 46}}, // Super wide + {6, 1, {46, 1399}}, // Super tall + {0, 2, {216, 280}}, // ANSI Letter + {1, 2, {214, 303}}, // ISO 216 A4 + {2, 2, {255, 255}}, // Square + {3, 2, {571, 114}}, // Wide + {4, 2, {114, 571}}, // Tall + {5, 2, {1399, 46}}, // Super wide + {6, 2, {46, 1399}}, // Super tall + }; + + for (const auto& params : kGenerateThumbnailTestParams) { + TestGenerateThumbnail(*engine, params.page_index, params.device_pixel_ratio, + params.expected_thumbnail_size, + "variable_page_sizes"); + } +} + } // namespace chrome_pdf diff --git a/chromium/pdf/pdfium/pdfium_print.cc b/chromium/pdf/pdfium/pdfium_print.cc index be5dd656dda..ee5691a711c 100644 --- a/chromium/pdf/pdfium/pdfium_print.cc +++ b/chromium/pdf/pdfium/pdfium_print.cc @@ -317,7 +317,7 @@ bool PDFiumPrint::IsSourcePdfLandscape(FPDF_DOCUMENT doc) { DCHECK(pdf_page); bool is_source_landscape = - FPDF_GetPageWidth(pdf_page.get()) > FPDF_GetPageHeight(pdf_page.get()); + FPDF_GetPageWidthF(pdf_page.get()) > FPDF_GetPageHeightF(pdf_page.get()); return is_source_landscape; } @@ -423,8 +423,8 @@ ScopedFPDFDocument PDFiumPrint::CreateSinglePageRasterPdf( ScopedFPDFDocument temp_doc(FPDF_CreateNewDocument()); DCHECK(temp_doc); - double source_page_width = FPDF_GetPageWidth(page_to_print); - double source_page_height = FPDF_GetPageHeight(page_to_print); + float source_page_width = FPDF_GetPageWidthF(page_to_print); + float source_page_height = FPDF_GetPageHeightF(page_to_print); // For computing size in pixels, use a square dpi since the source PDF page // has square DPI. diff --git a/chromium/pdf/pdfium/pdfium_print_unittest.cc b/chromium/pdf/pdfium/pdfium_print_unittest.cc index 34a6f37a01b..28f472f0fe6 100644 --- a/chromium/pdf/pdfium/pdfium_print_unittest.cc +++ b/chromium/pdf/pdfium/pdfium_print_unittest.cc @@ -7,6 +7,7 @@ #include <memory> #include "base/hash/md5.h" +#include "base/optional.h" #include "base/stl_util.h" #include "pdf/pdfium/pdfium_engine.h" #include "pdf/pdfium/pdfium_engine_exports.h" @@ -17,6 +18,8 @@ #include "printing/pdf_render_settings.h" #include "printing/units.h" #include "testing/gmock/include/gmock/gmock.h" +#include "ui/gfx/geometry/rect.h" +#include "ui/gfx/geometry/size_f.h" namespace chrome_pdf { @@ -32,12 +35,7 @@ constexpr PP_Size kUSLetterSize = {612, 792}; constexpr PP_Rect kUSLetterRect = {{0, 0}, kUSLetterSize}; constexpr PP_Rect kPrintableAreaRect = {{18, 18}, {576, 733}}; -struct SizeDouble { - double width; - double height; -}; - -using ExpectedDimensions = std::vector<SizeDouble>; +using ExpectedDimensions = std::vector<gfx::SizeF>; void CheckPdfDimensions(const std::vector<uint8_t>& pdf_data, const ExpectedDimensions& expected_dimensions) { @@ -48,35 +46,35 @@ void CheckPdfDimensions(const std::vector<uint8_t>& pdf_data, ASSERT_EQ(expected_dimensions.size(), static_cast<size_t>(page_count)); for (int i = 0; i < page_count; ++i) { - double width; - double height; - ASSERT_TRUE(exports.GetPDFPageSizeByIndex(pdf_data, i, &width, &height)); - EXPECT_DOUBLE_EQ(expected_dimensions[i].width, width); - EXPECT_DOUBLE_EQ(expected_dimensions[i].height, height); + base::Optional<gfx::SizeF> page_size = + exports.GetPDFPageSizeByIndex(pdf_data, i); + ASSERT_TRUE(page_size.has_value()); + EXPECT_EQ(expected_dimensions[i], page_size.value()); } } void CheckPdfRendering(const std::vector<uint8_t>& pdf_data, int page_number, - const SizeDouble& size_in_points, + const gfx::SizeF& size_in_points, const char* expected_md5_hash) { - int width_in_pixels = printing::ConvertUnit( - size_in_points.width, printing::kPointsPerInch, printing::kDefaultPdfDpi); + int width_in_pixels = + printing::ConvertUnit(size_in_points.width(), printing::kPointsPerInch, + printing::kDefaultPdfDpi); int height_in_pixels = - printing::ConvertUnit(size_in_points.height, printing::kPointsPerInch, + printing::ConvertUnit(size_in_points.height(), printing::kPointsPerInch, printing::kDefaultPdfDpi); - const pp::Rect page_rect(width_in_pixels, height_in_pixels); + const gfx::Rect page_rect(width_in_pixels, height_in_pixels); std::vector<uint8_t> page_bitmap_data(kColorChannels * page_rect.width() * page_rect.height()); PDFEngineExports::RenderingSettings settings( - printing::kDefaultPdfDpi, printing::kDefaultPdfDpi, page_rect, + gfx::Size(printing::kDefaultPdfDpi, printing::kDefaultPdfDpi), page_rect, /*fit_to_bounds=*/true, /*stretch_to_bounds=*/false, /*keep_aspect_ratio=*/true, /*center_in_bounds=*/true, - /*autorotate=*/false, /*use_color=*/true); + /*autorotate=*/false, /*use_color=*/true, /*render_for_printing=*/true); PDFiumEngineExports exports; ASSERT_TRUE(exports.RenderPDFPageToBitmap(pdf_data, page_number, settings, diff --git a/chromium/pdf/pdfium/pdfium_range.cc b/chromium/pdf/pdfium/pdfium_range.cc index ce6f095083a..437b478b412 100644 --- a/chromium/pdf/pdfium/pdfium_range.cc +++ b/chromium/pdf/pdfium/pdfium_range.cc @@ -8,6 +8,7 @@ #include "base/strings/string_util.h" #include "pdf/pdfium/pdfium_api_string_buffer_adapter.h" #include "ui/gfx/geometry/point.h" +#include "ui/gfx/geometry/rect.h" namespace chrome_pdf { @@ -52,7 +53,7 @@ void PDFiumRange::SetCharCount(int char_count) { cached_screen_rects_zoom_ = 0; } -const std::vector<pp::Rect>& PDFiumRange::GetScreenRects( +const std::vector<gfx::Rect>& PDFiumRange::GetScreenRects( const gfx::Point& point, double zoom, PageOrientation orientation) const { @@ -83,7 +84,7 @@ const std::vector<pp::Rect>& PDFiumRange::GetScreenRects( double right; double bottom; FPDFText_GetRect(page_->GetTextPage(), i, &left, &top, &right, &bottom); - pp::Rect rect = + gfx::Rect rect = page_->PageToScreen(point, zoom, left, top, right, bottom, orientation); if (rect.IsEmpty()) continue; diff --git a/chromium/pdf/pdfium/pdfium_range.h b/chromium/pdf/pdfium/pdfium_range.h index 28223f00626..75512ec124a 100644 --- a/chromium/pdf/pdfium/pdfium_range.h +++ b/chromium/pdf/pdfium/pdfium_range.h @@ -11,8 +11,8 @@ #include "base/strings/string16.h" #include "pdf/page_orientation.h" #include "pdf/pdfium/pdfium_page.h" -#include "ppapi/cpp/rect.h" #include "ui/gfx/geometry/point.h" +#include "ui/gfx/geometry/rect.h" namespace chrome_pdf { @@ -40,7 +40,7 @@ class PDFiumRange { int char_count() const { return char_count_; } // Gets bounding rectangles of range in screen coordinates. - const std::vector<pp::Rect>& GetScreenRects( + const std::vector<gfx::Rect>& GetScreenRects( const gfx::Point& point, double zoom, PageOrientation orientation) const; @@ -56,7 +56,7 @@ class PDFiumRange { int char_count_; // Cache of ScreenRect, and the associated variables used when caching it. - mutable std::vector<pp::Rect> cached_screen_rects_; + mutable std::vector<gfx::Rect> cached_screen_rects_; mutable gfx::Point cached_screen_rects_point_; mutable double cached_screen_rects_zoom_ = 0; }; diff --git a/chromium/pdf/pdfium/pdfium_test_base.cc b/chromium/pdf/pdfium/pdfium_test_base.cc index 5e10938b6f0..f28fbc9de51 100644 --- a/chromium/pdf/pdfium/pdfium_test_base.cc +++ b/chromium/pdf/pdfium/pdfium_test_base.cc @@ -9,8 +9,11 @@ #include <utility> #include "base/check_op.h" +#include "base/memory/scoped_refptr.h" #include "build/build_config.h" #include "pdf/pdfium/pdfium_engine.h" +#include "pdf/pdfium/pdfium_form_filler.h" +#include "pdf/ppapi_migration/url_loader.h" #include "pdf/test/test_client.h" #include "pdf/test/test_document_loader.h" @@ -83,9 +86,8 @@ PDFiumTestBase::InitializeEngineWithoutLoading( const base::FilePath::CharType* pdf_name) { InitializeEngineResult result; - pp::URLLoader dummy_loader; - result.engine = - std::make_unique<PDFiumEngine>(client, /*enable_javascript=*/false); + result.engine = std::make_unique<PDFiumEngine>( + client, PDFiumFormFiller::ScriptOption::kNoJavaScript); client->set_engine(result.engine.get()); auto test_loader = @@ -94,7 +96,7 @@ PDFiumTestBase::InitializeEngineWithoutLoading( result.engine->SetDocumentLoaderForTesting(std::move(test_loader)); if (!result.engine->New("https://chromium.org/dummy.pdf", "") || - !result.engine->HandleDocumentLoad(dummy_loader)) { + !result.engine->HandleDocumentLoad(nullptr)) { client->set_engine(nullptr); result.engine = nullptr; result.document_loader = nullptr; diff --git a/chromium/pdf/ppapi_migration/geometry_conversions.cc b/chromium/pdf/ppapi_migration/geometry_conversions.cc index 7fd6d18584e..de989c5f0d4 100644 --- a/chromium/pdf/ppapi_migration/geometry_conversions.cc +++ b/chromium/pdf/ppapi_migration/geometry_conversions.cc @@ -10,6 +10,7 @@ #include "ui/gfx/geometry/point.h" #include "ui/gfx/geometry/point_f.h" #include "ui/gfx/geometry/rect.h" +#include "ui/gfx/geometry/rect_f.h" #include "ui/gfx/geometry/size.h" #include "ui/gfx/geometry/vector2d.h" @@ -36,6 +37,16 @@ PP_Rect PPRectFromRect(const gfx::Rect& rect) { return PP_MakeRectFromXYWH(rect.x(), rect.y(), rect.width(), rect.height()); } +gfx::RectF RectFFromPPFloatRect(const PP_FloatRect& pp_rect) { + return gfx::RectF(pp_rect.point.x, pp_rect.point.y, pp_rect.size.width, + pp_rect.size.height); +} + +PP_FloatRect PPFloatRectFromRectF(const gfx::RectF& rect) { + return PP_MakeFloatRectFromXYWH(rect.x(), rect.y(), rect.width(), + rect.height()); +} + gfx::Size SizeFromPPSize(const PP_Size& pp_size) { return gfx::Size(pp_size.width, pp_size.height); } diff --git a/chromium/pdf/ppapi_migration/geometry_conversions.h b/chromium/pdf/ppapi_migration/geometry_conversions.h index 40a111be5ec..a495d598bde 100644 --- a/chromium/pdf/ppapi_migration/geometry_conversions.h +++ b/chromium/pdf/ppapi_migration/geometry_conversions.h @@ -6,6 +6,7 @@ #define PDF_PPAPI_MIGRATION_GEOMETRY_CONVERSIONS_H_ struct PP_FloatPoint; +struct PP_FloatRect; struct PP_Point; struct PP_Rect; struct PP_Size; @@ -14,6 +15,7 @@ namespace gfx { class Point; class PointF; class Rect; +class RectF; class Size; class Vector2d; } // namespace gfx @@ -28,6 +30,9 @@ gfx::PointF PointFFromPPFloatPoint(const PP_FloatPoint& pp_point); gfx::Rect RectFromPPRect(const PP_Rect& pp_rect); PP_Rect PPRectFromRect(const gfx::Rect& rect); +gfx::RectF RectFFromPPFloatRect(const PP_FloatRect& pp_rect); +PP_FloatRect PPFloatRectFromRectF(const gfx::RectF& rect); + gfx::Size SizeFromPPSize(const PP_Size& pp_size); PP_Size PPSizeFromSize(const gfx::Size& size); diff --git a/chromium/pdf/ppapi_migration/geometry_conversions_unittest.cc b/chromium/pdf/ppapi_migration/geometry_conversions_unittest.cc index 20ee44a0e23..598e8136bd3 100644 --- a/chromium/pdf/ppapi_migration/geometry_conversions_unittest.cc +++ b/chromium/pdf/ppapi_migration/geometry_conversions_unittest.cc @@ -14,6 +14,7 @@ #include "ui/gfx/geometry/point.h" #include "ui/gfx/geometry/point_f.h" #include "ui/gfx/geometry/rect.h" +#include "ui/gfx/geometry/rect_f.h" #include "ui/gfx/geometry/size.h" #include "ui/gfx/geometry/vector2d.h" @@ -67,6 +68,32 @@ TEST(GeometryConversionsTest, PPRectFromRect) { EXPECT_EQ(pp_c_rect.size.height, 3); } +TEST(GeometryConversionsTest, RectFFromPPFloatRect) { + gfx::RectF rect = + RectFFromPPFloatRect(pp::FloatRect(-1.0f, 2.1f, 3.2f, 4.3f)); + EXPECT_EQ(rect, gfx::RectF(-1.0f, 2.1f, 3.2f, 4.3f)); + + rect = + RectFFromPPFloatRect(PP_MakeFloatRectFromXYWH(2.9f, -1.8f, 4.7f, 3.6f)); + EXPECT_EQ(rect, gfx::RectF(2.9f, -1.8f, 4.7f, 3.6f)); +} + +TEST(GeometryConversionsTest, PPFloatRectFromRectF) { + pp::FloatRect pp_cpp_rect = + PPFloatRectFromRectF(gfx::RectF(-1.1f, 2.3f, 3.5f, 4.7f)); + EXPECT_EQ(pp_cpp_rect.x(), -1.1f); + EXPECT_EQ(pp_cpp_rect.y(), 2.3f); + EXPECT_EQ(pp_cpp_rect.width(), 3.5f); + EXPECT_EQ(pp_cpp_rect.height(), 4.7f); + + PP_FloatRect pp_c_rect = + PPFloatRectFromRectF(gfx::RectF(2.2f, -1.4f, 4.6f, 3.8f)); + EXPECT_EQ(pp_c_rect.point.x, 2.2f); + EXPECT_EQ(pp_c_rect.point.y, -1.4f); + EXPECT_EQ(pp_c_rect.size.width, 4.6f); + EXPECT_EQ(pp_c_rect.size.height, 3.8f); +} + TEST(GeometryConversionsTest, SizeFromPPSize) { gfx::Size size = SizeFromPPSize(pp::Size(3, 4)); EXPECT_EQ(size, gfx::Size(3, 4)); diff --git a/chromium/pdf/ppapi_migration/input_event_conversions.cc b/chromium/pdf/ppapi_migration/input_event_conversions.cc index e2f659a5736..7c7b65d7fa6 100644 --- a/chromium/pdf/ppapi_migration/input_event_conversions.cc +++ b/chromium/pdf/ppapi_migration/input_event_conversions.cc @@ -74,20 +74,68 @@ chrome_pdf::InputEventMouseButtonType GetInputEventMouseButtonType( } } +bool IsKeyboardEventType(chrome_pdf::InputEventType event_type) { + switch (event_type) { + case chrome_pdf::InputEventType::kRawKeyDown: + case chrome_pdf::InputEventType::kKeyDown: + case chrome_pdf::InputEventType::kKeyUp: + case chrome_pdf::InputEventType::kChar: + return true; + default: + return false; + } +} + +bool IsMouseEventType(chrome_pdf::InputEventType event_type) { + switch (event_type) { + case chrome_pdf::InputEventType::kMouseDown: + case chrome_pdf::InputEventType::kMouseUp: + case chrome_pdf::InputEventType::kMouseMove: + case chrome_pdf::InputEventType::kMouseEnter: + case chrome_pdf::InputEventType::kMouseLeave: + return true; + default: + return false; + } +} + +bool IsTouchEventType(chrome_pdf::InputEventType event_type) { + switch (event_type) { + case chrome_pdf::InputEventType::kTouchStart: + case chrome_pdf::InputEventType::kTouchMove: + case chrome_pdf::InputEventType::kTouchEnd: + case chrome_pdf::InputEventType::kTouchCancel: + return true; + default: + return false; + } +} + } // namespace namespace chrome_pdf { +InputEvent::InputEvent(InputEventType event_type, + double time_stamp, + uint32_t modifiers) + : event_type_(event_type), time_stamp_(time_stamp), modifiers_(modifiers) {} + +InputEvent::InputEvent(const InputEvent& other) = default; + +InputEvent& InputEvent::operator=(const InputEvent& other) = default; + +InputEvent::~InputEvent() = default; + KeyboardInputEvent::KeyboardInputEvent(InputEventType event_type, double time_stamp, uint32_t modifiers, uint32_t keyboard_code, const std::string& key_char) - : event_type_(event_type), - time_stamp_(time_stamp), - modifiers_(modifiers), + : InputEvent(event_type, time_stamp, modifiers), keyboard_code_(keyboard_code), - key_char_(key_char) {} + key_char_(key_char) { + DCHECK(IsKeyboardEventType(GetEventType())); +} KeyboardInputEvent::KeyboardInputEvent(const KeyboardInputEvent& other) = default; @@ -104,13 +152,13 @@ MouseInputEvent::MouseInputEvent(InputEventType event_type, const gfx::Point& point, int32_t click_count, const gfx::Point& movement) - : event_type_(event_type), - time_stamp_(time_stamp), - modifiers_(modifiers), + : InputEvent(event_type, time_stamp, modifiers), mouse_button_type_(mouse_button_type), point_(point), click_count_(click_count), - movement_(movement) {} + movement_(movement) { + DCHECK(IsMouseEventType(GetEventType())); +} MouseInputEvent::MouseInputEvent(const MouseInputEvent& other) = default; @@ -124,11 +172,11 @@ TouchInputEvent::TouchInputEvent(InputEventType event_type, uint32_t modifiers, const gfx::PointF& target_touch_point, int32_t touch_count) - : event_type_(event_type), - time_stamp_(time_stamp), - modifiers_(modifiers), + : InputEvent(event_type, time_stamp, modifiers), target_touch_point_(target_touch_point), - touch_count_(touch_count) {} + touch_count_(touch_count) { + DCHECK(IsTouchEventType(GetEventType())); +} TouchInputEvent::TouchInputEvent(const TouchInputEvent& other) = default; @@ -137,6 +185,16 @@ TouchInputEvent& TouchInputEvent::operator=(const TouchInputEvent& other) = TouchInputEvent::~TouchInputEvent() = default; +NoneInputEvent::NoneInputEvent() + : InputEvent(InputEventType::kNone, 0, kInputEventModifierNone) {} + +NoneInputEvent::NoneInputEvent(const NoneInputEvent& other) = default; + +NoneInputEvent& NoneInputEvent::operator=(const NoneInputEvent& other) = + default; + +NoneInputEvent::~NoneInputEvent() = default; + KeyboardInputEvent GetKeyboardInputEvent(const pp::KeyboardInputEvent& event) { return KeyboardInputEvent(GetEventType(event.GetType()), event.GetTimeStamp(), event.GetModifiers(), event.GetKeyCode(), diff --git a/chromium/pdf/ppapi_migration/input_event_conversions.h b/chromium/pdf/ppapi_migration/input_event_conversions.h index 3d7c1e4d06f..3116080fed2 100644 --- a/chromium/pdf/ppapi_migration/input_event_conversions.h +++ b/chromium/pdf/ppapi_migration/input_event_conversions.h @@ -111,7 +111,31 @@ enum class InputEventMouseButtonType { kRight, }; -class KeyboardInputEvent { +class InputEvent { + public: + InputEventType GetEventType() const { return event_type_; } + + double GetTimeStamp() const { return time_stamp_; } + + uint32_t GetModifiers() const { return modifiers_; } + + protected: + // Base class is not intended to be instantiated directly. Use + // `NoneInputEvent` to get an event of type `InputEventType::kNone`. + InputEvent(InputEventType event_type, double time_stamp, uint32_t modifiers); + InputEvent(const InputEvent& other); + InputEvent& operator=(const InputEvent& other); + ~InputEvent(); + + private: + InputEventType event_type_; + // The units are in seconds, but are not measured relative to any particular + // epoch, so the most you can do is compare two values. + double time_stamp_; + uint32_t modifiers_; +}; + +class KeyboardInputEvent : public InputEvent { public: KeyboardInputEvent(InputEventType event_type, double time_stamp, @@ -122,27 +146,16 @@ class KeyboardInputEvent { KeyboardInputEvent& operator=(const KeyboardInputEvent& other); ~KeyboardInputEvent(); - const InputEventType& GetEventType() const { return event_type_; } - - double GetTimeStamp() const { return time_stamp_; } - - uint32_t GetModifiers() const { return modifiers_; } - uint32_t GetKeyCode() const { return keyboard_code_; } const std::string& GetKeyChar() const { return key_char_; } private: - InputEventType event_type_ = InputEventType::kNone; - // The units are in seconds, but are not measured relative to any particular - // epoch, so the most you can do is compare two values. - double time_stamp_ = 0; - uint32_t modifiers_ = kInputEventModifierNone; uint32_t keyboard_code_; std::string key_char_; }; -class MouseInputEvent { +class MouseInputEvent : public InputEvent { public: MouseInputEvent(InputEventType event_type, double time_stamp, @@ -155,12 +168,6 @@ class MouseInputEvent { MouseInputEvent& operator=(const MouseInputEvent& other); ~MouseInputEvent(); - const InputEventType& GetEventType() const { return event_type_; } - - double GetTimeStamp() const { return time_stamp_; } - - uint32_t GetModifiers() const { return modifiers_; } - const InputEventMouseButtonType& GetButton() const { return mouse_button_type_; } @@ -172,18 +179,13 @@ class MouseInputEvent { const gfx::Point& GetMovement() const { return movement_; } private: - InputEventType event_type_ = InputEventType::kNone; - // The units are in seconds, but are not measured relative to any particular - // epoch, so the most you can do is compare two values. - double time_stamp_ = 0; - uint32_t modifiers_ = kInputEventModifierNone; InputEventMouseButtonType mouse_button_type_; gfx::Point point_; int32_t click_count_ = 0; gfx::Point movement_; }; -class TouchInputEvent { +class TouchInputEvent : public InputEvent { public: TouchInputEvent(InputEventType event_type, double time_stamp, @@ -194,12 +196,6 @@ class TouchInputEvent { TouchInputEvent& operator=(const TouchInputEvent& other); ~TouchInputEvent(); - const InputEventType& GetEventType() const { return event_type_; } - - double GetTimeStamp() const { return time_stamp_; } - - uint32_t GetModifiers() const { return modifiers_; } - // `pp::TouchInputEvent` exposes a collection of target touch points. We can // get all the points by passing the index of the point in the collection. // However, with `chrome_pdf::TouchEvent` the number of target touch points @@ -210,13 +206,18 @@ class TouchInputEvent { int32_t GetTouchCount() const { return touch_count_; } private: - InputEventType event_type_ = InputEventType::kNone; - double time_stamp_ = 0; - uint32_t modifiers_ = kInputEventModifierNone; gfx::PointF target_touch_point_; int32_t touch_count_ = 0; }; +class NoneInputEvent : public InputEvent { + public: + NoneInputEvent(); + NoneInputEvent(const NoneInputEvent& other); + NoneInputEvent& operator=(const NoneInputEvent& other); + ~NoneInputEvent(); +}; + KeyboardInputEvent GetKeyboardInputEvent(const pp::KeyboardInputEvent& event); MouseInputEvent GetMouseInputEvent(const pp::MouseInputEvent& event); diff --git a/chromium/pdf/ppapi_migration/url_loader.cc b/chromium/pdf/ppapi_migration/url_loader.cc new file mode 100644 index 00000000000..3b199668fbe --- /dev/null +++ b/chromium/pdf/ppapi_migration/url_loader.cc @@ -0,0 +1,402 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "pdf/ppapi_migration/url_loader.h" + +#include <stddef.h> +#include <stdint.h> + +#include <algorithm> +#include <string> +#include <utility> + +#include "base/bind.h" +#include "base/callback.h" +#include "base/check_op.h" +#include "base/memory/weak_ptr.h" +#include "base/notreached.h" +#include "net/base/net_errors.h" +#include "net/cookies/site_for_cookies.h" +#include "net/http/http_util.h" +#include "pdf/ppapi_migration/callback.h" +#include "ppapi/c/pp_errors.h" +#include "ppapi/c/trusted/ppb_url_loader_trusted.h" +#include "ppapi/cpp/completion_callback.h" +#include "ppapi/cpp/instance_handle.h" +#include "ppapi/cpp/module.h" +#include "ppapi/cpp/url_loader.h" +#include "ppapi/cpp/url_request_info.h" +#include "ppapi/cpp/url_response_info.h" +#include "ppapi/cpp/var.h" +#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-shared.h" +#include "third_party/blink/public/platform/web_data.h" +#include "third_party/blink/public/platform/web_http_body.h" +#include "third_party/blink/public/platform/web_http_header_visitor.h" +#include "third_party/blink/public/platform/web_string.h" +#include "third_party/blink/public/platform/web_url.h" +#include "third_party/blink/public/platform/web_url_error.h" +#include "third_party/blink/public/platform/web_url_request.h" +#include "third_party/blink/public/platform/web_url_response.h" +#include "third_party/blink/public/web/web_associated_url_loader.h" +#include "third_party/blink/public/web/web_associated_url_loader_options.h" +#include "url/gurl.h" + +namespace chrome_pdf { + +namespace { + +// Taken from `content/renderer/pepper/url_response_info_util.cc`. +class HeadersToString final : public blink::WebHTTPHeaderVisitor { + public: + explicit HeadersToString(std::string& buffer_ref) : buffer_ref_(buffer_ref) {} + + void VisitHeader(const blink::WebString& name, + const blink::WebString& value) override { + if (!buffer_ref_.empty()) + buffer_ref_.append("\n"); + buffer_ref_.append(name.Utf8()); + buffer_ref_.append(": "); + buffer_ref_.append(value.Utf8()); + } + + private: + // Reference allows writing directly into `UrlResponse::headers`. + std::string& buffer_ref_; +}; + +} // namespace + +UrlRequest::UrlRequest() = default; +UrlRequest::UrlRequest(const UrlRequest& other) = default; +UrlRequest::UrlRequest(UrlRequest&& other) noexcept = default; +UrlRequest& UrlRequest::operator=(const UrlRequest& other) = default; +UrlRequest& UrlRequest::operator=(UrlRequest&& other) noexcept = default; +UrlRequest::~UrlRequest() = default; + +UrlResponse::UrlResponse() = default; +UrlResponse::UrlResponse(const UrlResponse& other) = default; +UrlResponse::UrlResponse(UrlResponse&& other) noexcept = default; +UrlResponse& UrlResponse::operator=(const UrlResponse& other) = default; +UrlResponse& UrlResponse::operator=(UrlResponse&& other) noexcept = default; +UrlResponse::~UrlResponse() = default; + +UrlLoader::UrlLoader() = default; +UrlLoader::~UrlLoader() = default; + +BlinkUrlLoader::BlinkUrlLoader(base::WeakPtr<Client> client) + : client_(std::move(client)) {} + +BlinkUrlLoader::~BlinkUrlLoader() = default; + +// Modeled on `content::PepperURLLoaderHost::OnHostMsgGrantUniversalAccess()`. +void BlinkUrlLoader::GrantUniversalAccess() { + DCHECK_EQ(state_, LoadingState::kWaitingToOpen); + grant_universal_access_ = true; +} + +// Modeled on `content::PepperURLLoaderHost::OnHostMsgOpen()`. +void BlinkUrlLoader::Open(const UrlRequest& request, ResultCallback callback) { + DCHECK_EQ(state_, LoadingState::kWaitingToOpen); + DCHECK(callback); + state_ = LoadingState::kOpening; + open_callback_ = std::move(callback); + + if (!client_ || !client_->IsValid()) { + AbortLoad(PP_ERROR_FAILED); + return; + } + + // Modeled on `content::CreateWebURLRequest()`. + // TODO(crbug.com/1129291): The original code performs additional validations + // that we probably don't need in the new process model. + blink::WebURLRequest blink_request; + blink_request.SetUrl( + client_->CompleteURL(blink::WebString::FromUTF8(request.url))); + blink_request.SetHttpMethod(blink::WebString::FromASCII(request.method)); + + blink_request.SetSiteForCookies(client_->SiteForCookies()); + blink_request.SetSkipServiceWorker(true); + + // Note: The PDF plugin doesn't set the `X-Requested-With` header. + if (!request.headers.empty()) { + net::HttpUtil::HeadersIterator it(request.headers.begin(), + request.headers.end(), "\n\r"); + while (it.GetNext()) { + blink_request.AddHttpHeaderField(blink::WebString::FromUTF8(it.name()), + blink::WebString::FromUTF8(it.values())); + } + } + + if (!request.body.empty()) { + blink::WebHTTPBody body; + body.Initialize(); + body.AppendData(request.body); + blink_request.SetHttpBody(body); + } + + if (!request.custom_referrer_url.empty()) { + client_->SetReferrerForRequest(blink_request, + GURL(request.custom_referrer_url)); + } + + buffer_lower_threshold_ = request.buffer_lower_threshold; + buffer_upper_threshold_ = request.buffer_upper_threshold; + DCHECK_GT(buffer_lower_threshold_, 0u); + DCHECK_LE(buffer_lower_threshold_, buffer_upper_threshold_); + + blink_request.SetRequestContext(blink::mojom::RequestContextType::PLUGIN); + blink_request.SetRequestDestination( + network::mojom::RequestDestination::kEmbed); + + // TODO(crbug.com/822081): Revisit whether we need universal access. + blink::WebAssociatedURLLoaderOptions options; + options.grant_universal_access = grant_universal_access_; + ignore_redirects_ = request.ignore_redirects; + blink_loader_ = client_->CreateAssociatedURLLoader(options); + blink_loader_->LoadAsynchronously(blink_request, this); +} + +// Modeled on `ppapi::proxy::URLLoaderResource::ReadResponseBody()`. +void BlinkUrlLoader::ReadResponseBody(base::span<char> buffer, + ResultCallback callback) { + // Can be in `kLoadComplete` if still reading after loading finished. + DCHECK(state_ == LoadingState::kStreamingData || + state_ == LoadingState::kLoadComplete) + << static_cast<int>(state_); + + if (buffer.empty()) { + std::move(callback).Run(PP_ERROR_BADARGUMENT); + return; + } + + DCHECK(!read_callback_); + DCHECK(callback); + read_callback_ = std::move(callback); + client_buffer_ = buffer; + + if (!buffer_.empty() || state_ == LoadingState::kLoadComplete) + RunReadCallback(); +} + +// Modeled on `ppapi::proxy::URLLoadResource::Close()`. +void BlinkUrlLoader::Close() { + if (state_ != LoadingState::kLoadComplete) + AbortLoad(PP_ERROR_ABORTED); +} + +// Modeled on `content::PepperURLLoaderHost::WillFollowRedirect()`. +bool BlinkUrlLoader::WillFollowRedirect( + const blink::WebURL& new_url, + const blink::WebURLResponse& redirect_response) { + DCHECK_EQ(state_, LoadingState::kOpening); + + // TODO(crbug.com/1129291): The original code performs additional validations + // that we probably don't need in the new process model. + + // Note that `pp::URLLoader::FollowRedirect()` is not supported, so the + // redirect can be canceled immediately by returning `false` here. + return !ignore_redirects_; +} + +void BlinkUrlLoader::DidSendData(uint64_t bytes_sent, + uint64_t total_bytes_to_be_sent) { + // Doesn't apply to PDF viewer requests. + NOTREACHED(); +} + +// Modeled on `content::PepperURLLoaderHost::DidReceiveResponse()`. +void BlinkUrlLoader::DidReceiveResponse(const blink::WebURLResponse& response) { + DCHECK_EQ(state_, LoadingState::kOpening); + + // Modeled on `content::DataFromWebURLResponse()`. + mutable_response().status_code = response.HttpStatusCode(); + + HeadersToString headers_to_string(mutable_response().headers); + response.VisitHttpHeaderFields(&headers_to_string); + + state_ = LoadingState::kStreamingData; + std::move(open_callback_).Run(PP_OK); +} + +void BlinkUrlLoader::DidDownloadData(uint64_t data_length) { + // Doesn't apply to PDF viewer requests. + NOTREACHED(); +} + +// Modeled on `content::PepperURLLoaderHost::DidReceiveData()`. +void BlinkUrlLoader::DidReceiveData(const char* data, int data_length) { + DCHECK_EQ(state_, LoadingState::kStreamingData); + + // It's surprisingly difficult to guarantee that this is always >0. + if (data_length < 1) + return; + + buffer_.insert(buffer_.end(), data, data + data_length); + + // Defer loading if the buffer is too full. + if (!deferring_loading_ && buffer_.size() >= buffer_upper_threshold_) { + deferring_loading_ = true; + blink_loader_->SetDefersLoading(true); + } + + RunReadCallback(); +} + +void BlinkUrlLoader::DidReceiveCachedMetadata(const char* data, + int data_length) { + // Doesn't apply to PDF viewer requests. + NOTREACHED(); +} + +// Modeled on `content::PepperURLLoaderHost::DidFinishLoading()`. +void BlinkUrlLoader::DidFinishLoading() { + DCHECK_EQ(state_, LoadingState::kStreamingData); + + SetLoadComplete(PP_OK); + RunReadCallback(); +} + +// Modeled on `content::PepperURLLoaderHost::DidFail()`. +void BlinkUrlLoader::DidFail(const blink::WebURLError& error) { + DCHECK(state_ == LoadingState::kOpening || + state_ == LoadingState::kStreamingData) + << static_cast<int>(state_); + + int32_t pp_error = PP_ERROR_FAILED; + switch (error.reason()) { + case net::ERR_ACCESS_DENIED: + case net::ERR_NETWORK_ACCESS_DENIED: + pp_error = PP_ERROR_NOACCESS; + break; + + default: + if (error.is_web_security_violation()) + pp_error = PP_ERROR_NOACCESS; + break; + } + + AbortLoad(pp_error); +} + +void BlinkUrlLoader::AbortLoad(int32_t result) { + DCHECK_LT(result, 0); + + SetLoadComplete(result); + buffer_.clear(); + + if (open_callback_) { + DCHECK(!read_callback_); + std::move(open_callback_).Run(complete_result_); + } else if (read_callback_) { + RunReadCallback(); + } +} + +// Modeled on `ppapi::proxy::URLLoaderResource::FillUserBuffer()`. +void BlinkUrlLoader::RunReadCallback() { + if (!read_callback_) + return; + + DCHECK(!client_buffer_.empty()); + int32_t num_bytes = std::min( + {buffer_.size(), client_buffer_.size(), static_cast<size_t>(INT32_MAX)}); + if (num_bytes > 0) { + auto read_begin = buffer_.begin(); + auto read_end = read_begin + num_bytes; + std::copy(read_begin, read_end, client_buffer_.data()); + buffer_.erase(read_begin, read_end); + + // Resume loading if the buffer is too empty. + if (deferring_loading_ && buffer_.size() <= buffer_lower_threshold_) { + deferring_loading_ = false; + blink_loader_->SetDefersLoading(false); + } + } else { + DCHECK_EQ(state_, LoadingState::kLoadComplete); + num_bytes = complete_result_; + DCHECK_LE(num_bytes, 0); + static_assert(PP_OK == 0, "PP_OK should be equivalent to 0 bytes"); + } + + client_buffer_ = {}; + std::move(read_callback_).Run(num_bytes); +} + +void BlinkUrlLoader::SetLoadComplete(int32_t result) { + DCHECK_NE(state_, LoadingState::kLoadComplete); + DCHECK_LE(result, 0); + + state_ = LoadingState::kLoadComplete; + complete_result_ = result; + blink_loader_.reset(); +} + +PepperUrlLoader::PepperUrlLoader(pp::InstanceHandle plugin_instance) + : plugin_instance_(plugin_instance), pepper_loader_(plugin_instance) {} + +PepperUrlLoader::~PepperUrlLoader() = default; + +void PepperUrlLoader::GrantUniversalAccess() { + const PPB_URLLoaderTrusted* trusted_interface = + static_cast<const PPB_URLLoaderTrusted*>( + pp::Module::Get()->GetBrowserInterface( + PPB_URLLOADERTRUSTED_INTERFACE)); + if (trusted_interface) + trusted_interface->GrantUniversalAccess(pepper_loader_.pp_resource()); +} + +void PepperUrlLoader::Open(const UrlRequest& request, ResultCallback callback) { + pp::URLRequestInfo pp_request(plugin_instance_); + pp_request.SetURL(request.url); + pp_request.SetMethod(request.method); + + if (request.ignore_redirects) + pp_request.SetFollowRedirects(false); + + if (!request.custom_referrer_url.empty()) + pp_request.SetCustomReferrerURL(request.custom_referrer_url); + + if (!request.headers.empty()) + pp_request.SetHeaders(request.headers); + + if (!request.body.empty()) + pp_request.AppendDataToBody(request.body.data(), request.body.size()); + + pp::CompletionCallback pp_callback = PPCompletionCallbackFromResultCallback( + base::BindOnce(&PepperUrlLoader::DidOpen, weak_factory_.GetWeakPtr(), + std::move(callback))); + int32_t result = pepper_loader_.Open(pp_request, pp_callback); + if (result != PP_OK_COMPLETIONPENDING) + pp_callback.Run(result); +} + +void PepperUrlLoader::ReadResponseBody(base::span<char> buffer, + ResultCallback callback) { + pp::CompletionCallback pp_callback = + PPCompletionCallbackFromResultCallback(std::move(callback)); + int32_t result = pepper_loader_.ReadResponseBody(buffer.data(), buffer.size(), + pp_callback); + if (result != PP_OK_COMPLETIONPENDING) + pp_callback.Run(result); +} + +void PepperUrlLoader::Close() { + pepper_loader_.Close(); +} + +void PepperUrlLoader::DidOpen(ResultCallback callback, int32_t result) { + pp::URLResponseInfo pp_response = pepper_loader_.GetResponseInfo(); + mutable_response().status_code = pp_response.GetStatusCode(); + + pp::Var headers_var = pp_response.GetHeaders(); + if (headers_var.is_string()) { + mutable_response().headers = headers_var.AsString(); + } else { + mutable_response().headers.clear(); + } + + std::move(callback).Run(result); +} + +} // namespace chrome_pdf diff --git a/chromium/pdf/ppapi_migration/url_loader.h b/chromium/pdf/ppapi_migration/url_loader.h new file mode 100644 index 00000000000..30e76370bb1 --- /dev/null +++ b/chromium/pdf/ppapi_migration/url_loader.h @@ -0,0 +1,256 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PDF_PPAPI_MIGRATION_URL_LOADER_H_ +#define PDF_PPAPI_MIGRATION_URL_LOADER_H_ + +#include <stddef.h> +#include <stdint.h> + +#include <memory> +#include <string> + +#include "base/callback.h" +#include "base/containers/circular_deque.h" +#include "base/containers/span.h" +#include "base/memory/weak_ptr.h" +#include "pdf/ppapi_migration/callback.h" +#include "ppapi/cpp/instance_handle.h" +#include "ppapi/cpp/url_loader.h" +#include "third_party/blink/public/web/web_associated_url_loader_client.h" + +namespace blink { +class WebAssociatedURLLoader; +class WebString; +class WebURL; +class WebURLRequest; +struct WebAssociatedURLLoaderOptions; +} // namespace blink + +namespace net { +class SiteForCookies; +} // namespace net + +namespace chrome_pdf { + +// Properties for making a URL request. +struct UrlRequest final { + UrlRequest(); + UrlRequest(const UrlRequest& other); + UrlRequest(UrlRequest&& other) noexcept; + UrlRequest& operator=(const UrlRequest& other); + UrlRequest& operator=(UrlRequest&& other) noexcept; + ~UrlRequest(); + + // Request URL. + std::string url; + + // HTTP method. + std::string method; + + // Whether to ignore redirects. By default, redirects are followed + // automatically. + bool ignore_redirects = false; + + // Custom referrer URL. + std::string custom_referrer_url; + + // HTTP headers as a single string of `\n`-delimited key-value pairs. + std::string headers; + + // Request body. + std::string body; + + // Thresholds for throttling filling of the loader's internal buffer. Filling + // will stop after exceeding the upper threshold, and resume after dropping + // below the lower threshold. + // + // Default values taken from `ppapi/shared_impl/url_request_info_data.cc`. The + // PDF viewer never changes the defaults in production, so these fields mostly + // exist for testing purposes. + size_t buffer_lower_threshold = 50 * 1000 * 1000; + size_t buffer_upper_threshold = 100 * 1000 * 1000; +}; + +// Properties returned from a URL request. Does not include the response body. +struct UrlResponse final { + UrlResponse(); + UrlResponse(const UrlResponse& other); + UrlResponse(UrlResponse&& other) noexcept; + UrlResponse& operator=(const UrlResponse& other); + UrlResponse& operator=(UrlResponse&& other) noexcept; + ~UrlResponse(); + + // HTTP status code. + int32_t status_code = 0; + + // HTTP headers as a single string of `\n`-delimited key-value pairs. + std::string headers; +}; + +// Abstraction for a Blink or Pepper URL loader. +class UrlLoader { + public: + UrlLoader(const UrlLoader&) = delete; + UrlLoader& operator=(const UrlLoader&) = delete; + virtual ~UrlLoader(); + + // Tries to grant the loader the capability to make unrestricted cross-origin + // requests ("universal access," in `blink::SecurityOrigin` terms). Must be + // called before `Open()`. + virtual void GrantUniversalAccess() = 0; + + // Mimic `pp::URLLoader`: + virtual void Open(const UrlRequest& request, ResultCallback callback) = 0; + virtual void ReadResponseBody(base::span<char> buffer, + ResultCallback callback) = 0; + virtual void Close() = 0; + + // Returns the URL response (not including the body). Only valid after + // `Open()` completes. + const UrlResponse& response() const { return response_; } + + protected: + UrlLoader(); + + UrlResponse& mutable_response() { return response_; } + + private: + UrlResponse response_; +}; + +// A Blink URL loader. This implementation tries to emulate a combination of +// `content::PepperURLLoaderHost` and `ppapi::proxy::URLLoaderResource`. +class BlinkUrlLoader final : public UrlLoader, + public blink::WebAssociatedURLLoaderClient { + public: + // Client interface required by `BlinkUrlLoader`. Instances should be passed + // using weak pointers, as the loader can be shared, and may outlive the + // client. + class Client { + public: + // Returns `true` if the client is still usable. The client may require + // resources that can become unavailable, such as a local frame. Rather than + // handling missing resources separately for each method, callers can just + // verify validity once, before making any other calls. + virtual bool IsValid() const = 0; + + // Completes `partial_url` using the current document. + virtual blink::WebURL CompleteURL( + const blink::WebString& partial_url) const = 0; + + // Gets the site-for-cookies for the current document. + virtual net::SiteForCookies SiteForCookies() const = 0; + + // Sets the referrer on `request` to `referrer_url` using the current frame. + virtual void SetReferrerForRequest(blink::WebURLRequest& request, + const blink::WebURL& referrer_url) = 0; + + // Returns a new `blink::WebAssociatedURLLoader` from the current frame. + virtual std::unique_ptr<blink::WebAssociatedURLLoader> + CreateAssociatedURLLoader( + const blink::WebAssociatedURLLoaderOptions& options) = 0; + + protected: + ~Client() = default; + }; + + explicit BlinkUrlLoader(base::WeakPtr<Client> client); + BlinkUrlLoader(const BlinkUrlLoader&) = delete; + BlinkUrlLoader& operator=(const BlinkUrlLoader&) = delete; + ~BlinkUrlLoader() override; + + // UrlLoader: + void GrantUniversalAccess() override; + void Open(const UrlRequest& request, ResultCallback callback) override; + void ReadResponseBody(base::span<char> buffer, + ResultCallback callback) override; + void Close() override; + + // blink::WebAssociatedURLLoaderClient: + bool WillFollowRedirect( + const blink::WebURL& new_url, + const blink::WebURLResponse& redirect_response) override; + void DidSendData(uint64_t bytes_sent, + uint64_t total_bytes_to_be_sent) override; + void DidReceiveResponse(const blink::WebURLResponse& response) override; + void DidDownloadData(uint64_t data_length) override; + void DidReceiveData(const char* data, int data_length) override; + void DidReceiveCachedMetadata(const char* data, int data_length) override; + void DidFinishLoading() override; + void DidFail(const blink::WebURLError& error) override; + + private: + enum class LoadingState { + // Before calling `Open()`. + kWaitingToOpen, + + // After calling `Open()`, but before `DidReceiveResponse()` or `DidFail()`. + kOpening, + + // After `DidReceiveResponse()`, but before `DidFinishLoading()` or + // `DidFail()`. Zero or more calls allowed to `DidReceiveData()`. + kStreamingData, + + // After `DidFinishLoading()` or `DidFail()`, or forced by `Close()`. + // Details about how the load completed are in `complete_result_`. + kLoadComplete, + }; + + // Aborts the load with `result`. Runs callback if pending. + void AbortLoad(int32_t result); + + // Runs callback for `ReadResponseBody()` if pending. + void RunReadCallback(); + + void SetLoadComplete(int32_t result); + + base::WeakPtr<Client> client_; + bool grant_universal_access_ = false; + + LoadingState state_ = LoadingState::kWaitingToOpen; + int32_t complete_result_ = 0; + + std::unique_ptr<blink::WebAssociatedURLLoader> blink_loader_; + + bool ignore_redirects_ = false; + ResultCallback open_callback_; + + // Thresholds control buffer throttling, as defined in `UrlRequest`. + size_t buffer_lower_threshold_ = 0; + size_t buffer_upper_threshold_ = 0; + bool deferring_loading_ = false; + base::circular_deque<char> buffer_; + + ResultCallback read_callback_; + base::span<char> client_buffer_; +}; + +// A Pepper URL loader. +class PepperUrlLoader final : public UrlLoader { + public: + explicit PepperUrlLoader(pp::InstanceHandle plugin_instance); + PepperUrlLoader(const PepperUrlLoader&) = delete; + PepperUrlLoader& operator=(const PepperUrlLoader&) = delete; + ~PepperUrlLoader() override; + + // UrlLoader: + void GrantUniversalAccess() override; + void Open(const UrlRequest& request, ResultCallback callback) override; + void ReadResponseBody(base::span<char> buffer, + ResultCallback callback) override; + void Close() override; + + private: + void DidOpen(ResultCallback callback, int32_t result); + + pp::InstanceHandle plugin_instance_; + pp::URLLoader pepper_loader_; + + base::WeakPtrFactory<PepperUrlLoader> weak_factory_{this}; +}; + +} // namespace chrome_pdf + +#endif // PDF_PPAPI_MIGRATION_URL_LOADER_H_ diff --git a/chromium/pdf/ppapi_migration/url_loader_unittest.cc b/chromium/pdf/ppapi_migration/url_loader_unittest.cc new file mode 100644 index 00000000000..df79207c6b6 --- /dev/null +++ b/chromium/pdf/ppapi_migration/url_loader_unittest.cc @@ -0,0 +1,661 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "pdf/ppapi_migration/url_loader.h" + +#include <stddef.h> + +#include <memory> +#include <string> +#include <utility> +#include <vector> + +#include "base/bind.h" +#include "base/callback.h" +#include "base/containers/span.h" +#include "base/memory/weak_ptr.h" +#include "base/single_thread_task_runner.h" +#include "base/strings/string_split.h" +#include "base/strings/string_util.h" +#include "base/test/mock_callback.h" +#include "net/base/net_errors.h" +#include "net/cookies/site_for_cookies.h" +#include "pdf/ppapi_migration/callback.h" +#include "ppapi/c/pp_errors.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-shared.h" +#include "third_party/blink/public/platform/web_data.h" +#include "third_party/blink/public/platform/web_http_body.h" +#include "third_party/blink/public/platform/web_http_header_visitor.h" +#include "third_party/blink/public/platform/web_string.h" +#include "third_party/blink/public/platform/web_url.h" +#include "third_party/blink/public/platform/web_url_error.h" +#include "third_party/blink/public/platform/web_url_request.h" +#include "third_party/blink/public/platform/web_url_response.h" +#include "third_party/blink/public/web/web_associated_url_loader.h" +#include "third_party/blink/public/web/web_associated_url_loader_client.h" +#include "third_party/blink/public/web/web_associated_url_loader_options.h" +#include "url/gurl.h" + +namespace chrome_pdf { +namespace { + +using ::testing::Each; +using ::testing::ElementsAreArray; +using ::testing::InSequence; +using ::testing::Invoke; +using ::testing::NiceMock; +using ::testing::Return; +using ::testing::ReturnNull; +using ::testing::SaveArg; +using ::testing::UnorderedElementsAreArray; + +constexpr char kOriginUrl[] = "http://example.com/"; +constexpr char kDocumentUrl[] = "http://example.com/embedder/index.html"; +constexpr base::span<const char> kFakeData = "fake data"; + +size_t GetRequestHeaderCount(const blink::WebURLRequest& request) { + struct : public blink::WebHTTPHeaderVisitor { + void VisitHeader(const blink::WebString& name, + const blink::WebString& value) override { + ++count; + } + + size_t count = 0; + } counting_header_visitor; + + request.VisitHttpHeaderFields(&counting_header_visitor); + return counting_header_visitor.count; +} + +blink::WebURLError MakeWebURLError(int reason) { + return blink::WebURLError(reason, GURL()); +} + +class MockWebAssociatedURLLoader : public blink::WebAssociatedURLLoader { + public: + // blink::WebAssociatedURLLoader: + MOCK_METHOD(void, + LoadAsynchronously, + (const blink::WebURLRequest&, + blink::WebAssociatedURLLoaderClient*), + (override)); + MOCK_METHOD(void, Cancel, (), (override)); + MOCK_METHOD(void, SetDefersLoading, (bool), (override)); + MOCK_METHOD(void, + SetLoadingTaskRunner, + (base::SingleThreadTaskRunner*), + (override)); +}; + +class FakeBlinkUrlLoaderClient : public BlinkUrlLoader::Client { + public: + base::WeakPtr<FakeBlinkUrlLoaderClient> GetWeakPtr() { + return weak_factory_.GetWeakPtr(); + } + + void InvalidateWeakPtrs() { weak_factory_.InvalidateWeakPtrs(); } + + void Invalidate() { valid_ = false; } + + MockWebAssociatedURLLoader* mock_url_loader() { + return mock_url_loader_.get(); + } + + const blink::WebAssociatedURLLoaderOptions& saved_options() const { + return saved_options_; + } + + // BlinkUrlLoader::Client: + bool IsValid() const override { return valid_; } + + blink::WebURL CompleteURL( + const blink::WebString& partial_url) const override { + EXPECT_TRUE(IsValid()); + return GURL(kDocumentUrl).Resolve(partial_url.Utf8()); + } + + net::SiteForCookies SiteForCookies() const override { + EXPECT_TRUE(IsValid()); + return net::SiteForCookies::FromUrl(GURL(kOriginUrl)); + } + + void SetReferrerForRequest(blink::WebURLRequest& request, + const blink::WebURL& referrer_url) override { + EXPECT_FALSE(referrer_url.IsEmpty()); + EXPECT_TRUE(IsValid()); + request.SetReferrerString(referrer_url.GetString()); + } + + std::unique_ptr<blink::WebAssociatedURLLoader> CreateAssociatedURLLoader( + const blink::WebAssociatedURLLoaderOptions& options) override { + EXPECT_TRUE(IsValid()); + EXPECT_TRUE(mock_url_loader_); + saved_options_ = options; + return std::move(mock_url_loader_); + } + + private: + bool valid_ = true; + + std::unique_ptr<NiceMock<MockWebAssociatedURLLoader>> mock_url_loader_ = + std::make_unique<NiceMock<MockWebAssociatedURLLoader>>(); + blink::WebAssociatedURLLoaderOptions saved_options_; + + base::WeakPtrFactory<FakeBlinkUrlLoaderClient> weak_factory_{this}; +}; + +class BlinkUrlLoaderTest : public testing::Test { + protected: + BlinkUrlLoaderTest() { + ON_CALL(*mock_url_loader_, LoadAsynchronously) + .WillByDefault( + Invoke(this, &BlinkUrlLoaderTest::FakeLoadAsynchronously)); + loader_ = std::make_unique<BlinkUrlLoader>(fake_client_.GetWeakPtr()); + } + + void FakeLoadAsynchronously(const blink::WebURLRequest& request, + blink::WebAssociatedURLLoaderClient* client) { + saved_request_.CopyFrom(request); + EXPECT_EQ(loader_.get(), client); + } + + void StartLoadWithThresholds(size_t lower, size_t upper) { + UrlRequest request; + request.buffer_lower_threshold = lower; + request.buffer_upper_threshold = upper; + loader_->Open(request, mock_callback_.Get()); + loader_->DidReceiveResponse(blink::WebURLResponse()); + } + + int32_t DidFailWithError(const blink::WebURLError& error) { + int32_t result = 0; + loader_->Open(UrlRequest(), mock_callback_.Get()); + EXPECT_CALL(mock_callback_, Run).WillOnce(SaveArg<0>(&result)); + + loader_->DidFail(error); + return result; + } + + FakeBlinkUrlLoaderClient fake_client_; + NiceMock<base::MockCallback<ResultCallback>> mock_callback_; + std::unique_ptr<BlinkUrlLoader> loader_; + + // Becomes invalid if `loader_` is closed or destructed. + MockWebAssociatedURLLoader* mock_url_loader_ = fake_client_.mock_url_loader(); + + blink::WebURLRequest saved_request_; +}; + +TEST_F(BlinkUrlLoaderTest, GrantUniversalAccess) { + loader_->GrantUniversalAccess(); + loader_->Open(UrlRequest(), mock_callback_.Get()); + EXPECT_TRUE(fake_client_.saved_options().grant_universal_access); +} + +TEST_F(BlinkUrlLoaderTest, Open) { + EXPECT_CALL(*mock_url_loader_, LoadAsynchronously); + EXPECT_CALL(mock_callback_, Run).Times(0); + + UrlRequest request; + request.url = "http://example.com/fake.pdf"; + request.method = "FAKE"; + loader_->Open(request, mock_callback_.Get()); + + EXPECT_FALSE(fake_client_.saved_options().grant_universal_access); + EXPECT_EQ(GURL("http://example.com/fake.pdf"), GURL(saved_request_.Url())); + EXPECT_EQ("FAKE", saved_request_.HttpMethod().Ascii()); + EXPECT_EQ(GURL(kOriginUrl), + saved_request_.SiteForCookies().RepresentativeUrl()); + EXPECT_TRUE(saved_request_.GetSkipServiceWorker()); + EXPECT_EQ(0u, GetRequestHeaderCount(saved_request_)); + EXPECT_EQ(blink::mojom::RequestContextType::PLUGIN, + saved_request_.GetRequestContext()); + EXPECT_EQ(network::mojom::RequestDestination::kEmbed, + saved_request_.GetRequestDestination()); +} + +TEST_F(BlinkUrlLoaderTest, OpenWithInvalidatedClientWeakPtr) { + EXPECT_CALL(*mock_url_loader_, LoadAsynchronously).Times(0); + EXPECT_CALL(mock_callback_, Run(PP_ERROR_FAILED)); + + fake_client_.InvalidateWeakPtrs(); + loader_->Open(UrlRequest(), mock_callback_.Get()); +} + +TEST_F(BlinkUrlLoaderTest, OpenWithInvalidatedClient) { + EXPECT_CALL(*mock_url_loader_, LoadAsynchronously).Times(0); + EXPECT_CALL(mock_callback_, Run(PP_ERROR_FAILED)); + + fake_client_.Invalidate(); + loader_->Open(UrlRequest(), mock_callback_.Get()); +} + +TEST_F(BlinkUrlLoaderTest, OpenWithRelativeUrl) { + UrlRequest request; + request.url = "relative.pdf"; + loader_->Open(request, mock_callback_.Get()); + + EXPECT_EQ(GURL(kDocumentUrl).Resolve("relative.pdf"), + GURL(saved_request_.Url())); +} + +TEST_F(BlinkUrlLoaderTest, OpenWithHeaders) { + UrlRequest request; + request.headers = base::JoinString( + { + "Content-Length: 123", + "Content-Type: application/pdf", + "Non-ASCII-Value: 🙃", + }, + "\n"); + loader_->Open(request, mock_callback_.Get()); + + EXPECT_EQ(3u, GetRequestHeaderCount(saved_request_)); + EXPECT_EQ("123", saved_request_.HttpHeaderField("Content-Length").Utf8()); + EXPECT_EQ("application/pdf", + saved_request_.HttpHeaderField("Content-Type").Utf8()); + EXPECT_EQ("🙃", saved_request_.HttpHeaderField("Non-ASCII-Value").Utf8()); +} + +TEST_F(BlinkUrlLoaderTest, OpenWithBody) { + UrlRequest request; + request.body = "fake body"; + loader_->Open(request, mock_callback_.Get()); + + blink::WebHTTPBody request_body = saved_request_.HttpBody(); + EXPECT_EQ(1u, request_body.ElementCount()); + + blink::WebHTTPBody::Element element; + EXPECT_TRUE(request_body.ElementAt(0, element)); + EXPECT_EQ(blink::WebHTTPBody::Element::kTypeData, element.type); + + std::string data; + element.data.ForEachSegment( + [&](const char* segment, size_t length, size_t pos) { + data.append(segment, length); + return true; + }); + EXPECT_EQ("fake body", data); +} + +TEST_F(BlinkUrlLoaderTest, OpenWithCustomReferrerUrl) { + UrlRequest request; + request.custom_referrer_url = "http://example.com/referrer"; + loader_->Open(request, mock_callback_.Get()); + + EXPECT_EQ("http://example.com/referrer", + saved_request_.ReferrerString().Utf8()); +} + +TEST_F(BlinkUrlLoaderTest, WillFollowRedirect) { + loader_->Open(UrlRequest(), mock_callback_.Get()); + + EXPECT_TRUE(loader_->WillFollowRedirect(GURL("http://example.com/login"), + blink::WebURLResponse())); +} + +TEST_F(BlinkUrlLoaderTest, WillFollowRedirectWhileIgnoringRedirects) { + UrlRequest request; + request.ignore_redirects = true; + loader_->Open(request, mock_callback_.Get()); + + EXPECT_FALSE(loader_->WillFollowRedirect(GURL("http://example.com/login"), + blink::WebURLResponse())); +} + +TEST_F(BlinkUrlLoaderTest, DidReceiveResponse) { + loader_->Open(UrlRequest(), mock_callback_.Get()); + EXPECT_CALL(mock_callback_, Run(PP_OK)); + + blink::WebURLResponse response; + response.SetHttpStatusCode(204); + loader_->DidReceiveResponse(response); + + EXPECT_EQ(204, loader_->response().status_code); + EXPECT_EQ("", loader_->response().headers); +} + +TEST_F(BlinkUrlLoaderTest, DidReceiveResponseWithHeaders) { + loader_->Open(UrlRequest(), mock_callback_.Get()); + + blink::WebURLResponse response; + response.AddHttpHeaderField("Content-Length", "123"); + response.AddHttpHeaderField("Content-Type", "application/pdf"); + response.AddHttpHeaderField("Non-ASCII-Value", "🙃"); + loader_->DidReceiveResponse(response); + + std::vector<std::string> split_headers = + base::SplitString(loader_->response().headers, "\n", + base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL); + EXPECT_THAT(split_headers, UnorderedElementsAreArray({ + "Content-Length: 123", + "Content-Type: application/pdf", + "Non-ASCII-Value: 🙃", + })); +} + +TEST_F(BlinkUrlLoaderTest, DidReceiveData) { + char buffer[kFakeData.size()] = {}; + loader_->Open(UrlRequest(), mock_callback_.Get()); + loader_->DidReceiveResponse(blink::WebURLResponse()); + loader_->ReadResponseBody(buffer, mock_callback_.Get()); + EXPECT_CALL(mock_callback_, Run(kFakeData.size())); + + loader_->DidReceiveData(kFakeData.data(), kFakeData.size()); + + EXPECT_THAT(buffer, ElementsAreArray(kFakeData)); +} + +TEST_F(BlinkUrlLoaderTest, DidReceiveDataWithZeroLength) { + char buffer[kFakeData.size()] = {}; + loader_->Open(UrlRequest(), mock_callback_.Get()); + loader_->DidReceiveResponse(blink::WebURLResponse()); + loader_->ReadResponseBody(buffer, mock_callback_.Get()); + EXPECT_CALL(mock_callback_, Run).Times(0); + + loader_->DidReceiveData(kFakeData.data(), 0); + + EXPECT_THAT(buffer, Each(0)); +} + +TEST_F(BlinkUrlLoaderTest, DidReceiveDataBelowUpperThreshold) { + StartLoadWithThresholds(/*lower=*/2, /*upper=*/4); + EXPECT_CALL(*mock_url_loader_, SetDefersLoading).Times(0); + + char buffer[3] = {}; + loader_->DidReceiveData(buffer, sizeof(buffer)); +} + +TEST_F(BlinkUrlLoaderTest, DidReceiveDataCrossUpperThreshold) { + StartLoadWithThresholds(/*lower=*/2, /*upper=*/4); + + char read_buffer[1]; + loader_->ReadResponseBody(read_buffer, mock_callback_.Get()); + { + InSequence defer_before_read_callback; + EXPECT_CALL(*mock_url_loader_, SetDefersLoading(true)); + EXPECT_CALL(mock_callback_, Run); + } + + char buffer[4] = {}; + loader_->DidReceiveData(buffer, sizeof(buffer)); +} + +TEST_F(BlinkUrlLoaderTest, DidReceiveDataAboveUpperThreshold) { + StartLoadWithThresholds(/*lower=*/2, /*upper=*/4); + + char buffer[4] = {}; + loader_->DidReceiveData(buffer, sizeof(buffer)); + EXPECT_CALL(*mock_url_loader_, SetDefersLoading).Times(0); + + loader_->DidReceiveData(buffer, sizeof(buffer)); +} + +TEST_F(BlinkUrlLoaderTest, ReadResponseBody) { + loader_->Open(UrlRequest(), mock_callback_.Get()); + loader_->DidReceiveResponse(blink::WebURLResponse()); + loader_->DidReceiveData(kFakeData.data(), kFakeData.size()); + EXPECT_CALL(mock_callback_, Run(kFakeData.size())); + + char buffer[kFakeData.size()] = {}; + loader_->ReadResponseBody(buffer, mock_callback_.Get()); + + EXPECT_THAT(buffer, ElementsAreArray(kFakeData)); + + // Verify no more data returned on next call. + EXPECT_CALL(mock_callback_, Run).Times(0); + loader_->ReadResponseBody(buffer, mock_callback_.Get()); +} + +TEST_F(BlinkUrlLoaderTest, ReadResponseBodyWithoutData) { + loader_->Open(UrlRequest(), mock_callback_.Get()); + loader_->DidReceiveResponse(blink::WebURLResponse()); + EXPECT_CALL(mock_callback_, Run).Times(0); + + char buffer[kFakeData.size()] = {}; + loader_->ReadResponseBody(buffer, mock_callback_.Get()); + + EXPECT_THAT(buffer, Each(0)); +} + +TEST_F(BlinkUrlLoaderTest, ReadResponseBodyWithEmptyBuffer) { + loader_->Open(UrlRequest(), mock_callback_.Get()); + loader_->DidReceiveResponse(blink::WebURLResponse()); + EXPECT_CALL(mock_callback_, Run(PP_ERROR_BADARGUMENT)); + + loader_->ReadResponseBody(base::span<char>(), mock_callback_.Get()); +} + +TEST_F(BlinkUrlLoaderTest, ReadResponseBodyWithSmallerBuffer) { + static constexpr size_t kTailSize = 1; + static constexpr size_t kBufferSize = kFakeData.size() - kTailSize; + + loader_->Open(UrlRequest(), mock_callback_.Get()); + loader_->DidReceiveResponse(blink::WebURLResponse()); + loader_->DidReceiveData(kFakeData.data(), kFakeData.size()); + EXPECT_CALL(mock_callback_, Run(kBufferSize)); + + char buffer[kBufferSize] = {}; + loader_->ReadResponseBody(buffer, mock_callback_.Get()); + + EXPECT_THAT(buffer, ElementsAreArray(kFakeData.first(kBufferSize))); + + // Verify remaining data returned on next call. + char tail_buffer[kTailSize]; + EXPECT_CALL(mock_callback_, Run(kTailSize)); + loader_->ReadResponseBody(tail_buffer, mock_callback_.Get()); + EXPECT_THAT(tail_buffer, ElementsAreArray(kFakeData.subspan(kBufferSize))); +} + +TEST_F(BlinkUrlLoaderTest, ReadResponseBodyWithBiggerBuffer) { + loader_->Open(UrlRequest(), mock_callback_.Get()); + loader_->DidReceiveResponse(blink::WebURLResponse()); + loader_->DidReceiveData(kFakeData.data(), kFakeData.size()); + EXPECT_CALL(mock_callback_, Run(kFakeData.size())); + + char buffer[kFakeData.size() + 1] = {}; + loader_->ReadResponseBody(buffer, mock_callback_.Get()); + + base::span<char> buffer_span = buffer; + EXPECT_THAT(buffer_span.first(kFakeData.size()), ElementsAreArray(kFakeData)); + EXPECT_THAT(buffer_span.subspan(kFakeData.size()), Each(0)); + + // Verify no more data returned on next call. + EXPECT_CALL(mock_callback_, Run).Times(0); + loader_->ReadResponseBody(buffer, mock_callback_.Get()); +} + +TEST_F(BlinkUrlLoaderTest, ReadResponseBodyWhileLoadComplete) { + loader_->Open(UrlRequest(), mock_callback_.Get()); + loader_->DidReceiveResponse(blink::WebURLResponse()); + loader_->DidReceiveData(kFakeData.data(), kFakeData.size()); + loader_->DidFinishLoading(); + EXPECT_CALL(mock_callback_, Run(kFakeData.size())); + + char buffer[kFakeData.size()] = {}; + loader_->ReadResponseBody(buffer, mock_callback_.Get()); + + EXPECT_THAT(buffer, ElementsAreArray(kFakeData)); + + // Verify no more data returned on next call. + char tail_buffer[kFakeData.size()] = {}; + EXPECT_CALL(mock_callback_, Run(0)); + loader_->ReadResponseBody(tail_buffer, mock_callback_.Get()); + EXPECT_THAT(tail_buffer, Each(0)); +} + +TEST_F(BlinkUrlLoaderTest, ReadResponseBodyWhileLoadCompleteWithoutData) { + loader_->Open(UrlRequest(), mock_callback_.Get()); + loader_->DidReceiveResponse(blink::WebURLResponse()); + loader_->DidFinishLoading(); + EXPECT_CALL(mock_callback_, Run(0)); + + char buffer[kFakeData.size()] = {}; + loader_->ReadResponseBody(buffer, mock_callback_.Get()); + + EXPECT_THAT(buffer, Each(0)); +} + +TEST_F(BlinkUrlLoaderTest, ReadResponseBodyWhileLoadCompleteWithError) { + loader_->Open(UrlRequest(), mock_callback_.Get()); + loader_->DidReceiveResponse(blink::WebURLResponse()); + loader_->DidReceiveData(kFakeData.data(), kFakeData.size()); + loader_->DidFail(MakeWebURLError(net::ERR_FAILED)); + EXPECT_CALL(mock_callback_, Run(PP_ERROR_FAILED)); + + char buffer[kFakeData.size()] = {}; + loader_->ReadResponseBody(buffer, mock_callback_.Get()); + + EXPECT_THAT(buffer, Each(0)); +} + +TEST_F(BlinkUrlLoaderTest, ReadResponseBodyAboveLowerThreshold) { + StartLoadWithThresholds(/*lower=*/2, /*upper=*/4); + + char write_buffer[5] = {}; + loader_->DidReceiveData(write_buffer, sizeof(write_buffer)); + EXPECT_CALL(*mock_url_loader_, SetDefersLoading).Times(0); + + char buffer[2] = {}; + loader_->ReadResponseBody(buffer, mock_callback_.Get()); +} + +TEST_F(BlinkUrlLoaderTest, ReadResponseBodyCrossLowerThreshold) { + StartLoadWithThresholds(/*lower=*/2, /*upper=*/4); + + char write_buffer[5] = {}; + loader_->DidReceiveData(write_buffer, sizeof(write_buffer)); + { + InSequence resume_before_read_callback; + EXPECT_CALL(*mock_url_loader_, SetDefersLoading(false)); + EXPECT_CALL(mock_callback_, Run); + } + + char buffer[3] = {}; + loader_->ReadResponseBody(buffer, mock_callback_.Get()); +} + +TEST_F(BlinkUrlLoaderTest, ReadResponseBodyBelowLowerThreshold) { + StartLoadWithThresholds(/*lower=*/2, /*upper=*/4); + + char write_buffer[5] = {}; + loader_->DidReceiveData(write_buffer, sizeof(write_buffer)); + + char buffer[3] = {}; + loader_->ReadResponseBody(buffer, mock_callback_.Get()); + EXPECT_CALL(*mock_url_loader_, SetDefersLoading).Times(0); + + loader_->ReadResponseBody(buffer, mock_callback_.Get()); +} + +TEST_F(BlinkUrlLoaderTest, DidFinishLoading) { + loader_->Open(UrlRequest(), mock_callback_.Get()); + loader_->DidReceiveResponse(blink::WebURLResponse()); + EXPECT_CALL(mock_callback_, Run).Times(0); + + loader_->DidFinishLoading(); +} + +TEST_F(BlinkUrlLoaderTest, DidFinishLoadingWithPendingCallback) { + char buffer[1]; + loader_->Open(UrlRequest(), mock_callback_.Get()); + loader_->DidReceiveResponse(blink::WebURLResponse()); + loader_->ReadResponseBody(buffer, mock_callback_.Get()); + EXPECT_CALL(mock_callback_, Run(0)); // Result represents read bytes. + + loader_->DidFinishLoading(); +} + +TEST_F(BlinkUrlLoaderTest, DidFailWhileOpening) { + loader_->Open(UrlRequest(), mock_callback_.Get()); + EXPECT_CALL(mock_callback_, Run(PP_ERROR_FAILED)); + + loader_->DidFail(MakeWebURLError(net::ERR_FAILED)); +} + +TEST_F(BlinkUrlLoaderTest, DidFailWhileStreamingData) { + char buffer[1]; + loader_->Open(UrlRequest(), mock_callback_.Get()); + loader_->DidReceiveResponse(blink::WebURLResponse()); + loader_->ReadResponseBody(buffer, mock_callback_.Get()); + EXPECT_CALL(mock_callback_, Run(PP_ERROR_FAILED)); + + loader_->DidFail(MakeWebURLError(net::ERR_FAILED)); +} + +TEST_F(BlinkUrlLoaderTest, DidFailWithErrorAccessDenied) { + int32_t result = DidFailWithError(MakeWebURLError(net::ERR_ACCESS_DENIED)); + + EXPECT_EQ(PP_ERROR_NOACCESS, result); +} + +TEST_F(BlinkUrlLoaderTest, DidFailWithErrorNetworkAccessDenied) { + int32_t result = + DidFailWithError(MakeWebURLError(net::ERR_NETWORK_ACCESS_DENIED)); + + EXPECT_EQ(PP_ERROR_NOACCESS, result); +} + +TEST_F(BlinkUrlLoaderTest, DidFailWithWebSecurityViolationError) { + blink::WebURLError error(network::CorsErrorStatus(), + blink::WebURLError::HasCopyInCache::kFalse, GURL()); + ASSERT_TRUE(error.is_web_security_violation()); + + int32_t result = DidFailWithError(error); + + EXPECT_EQ(PP_ERROR_NOACCESS, result); +} + +TEST_F(BlinkUrlLoaderTest, CloseWhileWaitingToOpen) { + EXPECT_CALL(mock_callback_, Run).Times(0); + + loader_->Close(); +} + +TEST_F(BlinkUrlLoaderTest, CloseWhileOpening) { + loader_->Open(UrlRequest(), mock_callback_.Get()); + EXPECT_CALL(mock_callback_, Run(PP_ERROR_ABORTED)); + + loader_->Close(); +} + +TEST_F(BlinkUrlLoaderTest, CloseWhileStreamingData) { + loader_->Open(UrlRequest(), mock_callback_.Get()); + loader_->DidReceiveResponse(blink::WebURLResponse()); + EXPECT_CALL(mock_callback_, Run).Times(0); + + loader_->Close(); +} + +TEST_F(BlinkUrlLoaderTest, CloseWhileStreamingDataWithPendingCallback) { + char buffer[1]; + loader_->Open(UrlRequest(), mock_callback_.Get()); + loader_->DidReceiveResponse(blink::WebURLResponse()); + loader_->ReadResponseBody(buffer, mock_callback_.Get()); + EXPECT_CALL(mock_callback_, Run(PP_ERROR_ABORTED)); + + loader_->Close(); +} + +TEST_F(BlinkUrlLoaderTest, CloseWhileLoadComplete) { + loader_->Open(UrlRequest(), mock_callback_.Get()); + loader_->DidReceiveResponse(blink::WebURLResponse()); + loader_->DidFinishLoading(); + EXPECT_CALL(mock_callback_, Run).Times(0); + + loader_->Close(); +} + +TEST_F(BlinkUrlLoaderTest, CloseAgain) { + loader_->Open(UrlRequest(), mock_callback_.Get()); + loader_->Close(); + EXPECT_CALL(mock_callback_, Run).Times(0); + + loader_->Close(); +} + +} // namespace +} // namespace chrome_pdf diff --git a/chromium/pdf/ppapi_migration/value_conversions.cc b/chromium/pdf/ppapi_migration/value_conversions.cc index 1890d89ba14..c0b894eadf2 100644 --- a/chromium/pdf/ppapi_migration/value_conversions.cc +++ b/chromium/pdf/ppapi_migration/value_conversions.cc @@ -6,6 +6,8 @@ #include <algorithm> +#include "base/containers/span.h" +#include "base/notreached.h" #include "base/values.h" #include "ppapi/cpp/var.h" #include "ppapi/cpp/var_array.h" @@ -55,4 +57,57 @@ pp::Var VarFromValue(const base::Value& value) { } } -} // namespace chrome_pdf
\ No newline at end of file +base::Value ValueFromVar(const pp::Var& var) { + switch (var.pp_var().type) { + case PP_VARTYPE_UNDEFINED: + return base::Value(); + case PP_VARTYPE_NULL: + return base::Value(); + case PP_VARTYPE_BOOL: + return base::Value(var.AsBool()); + case PP_VARTYPE_INT32: + return base::Value(var.AsInt()); + case PP_VARTYPE_DOUBLE: + return base::Value(var.AsDouble()); + case PP_VARTYPE_STRING: + return base::Value(var.AsString()); + case PP_VARTYPE_OBJECT: + // There is no valid conversion from PP_VARTYPE_OBJECT to a base::Value + // type. This should not be called to convert this type. + NOTREACHED(); + return base::Value(); + case PP_VARTYPE_ARRAY: { + pp::VarArray var_array(var); + base::Value::ListStorage list_storage(var_array.GetLength()); + for (uint32_t i = 0; i < var_array.GetLength(); ++i) { + list_storage[i] = ValueFromVar(var_array.Get(i)); + } + return base::Value(std::move(list_storage)); + } + case PP_VARTYPE_DICTIONARY: { + base::Value val_dictionary(base::Value::Type::DICTIONARY); + pp::VarDictionary var_dict(var); + pp::VarArray dict_keys = var_dict.GetKeys(); + for (uint32_t i = 0; i < dict_keys.GetLength(); ++i) { + pp::Var key = dict_keys.Get(i); + val_dictionary.SetKey(key.AsString(), ValueFromVar(var_dict.Get(key))); + } + return val_dictionary; + } + case PP_VARTYPE_ARRAY_BUFFER: { + pp::VarArrayBuffer var_array_buffer(var); + base::Value value( + base::make_span(static_cast<uint8_t*>(var_array_buffer.Map()), + var_array_buffer.ByteLength())); + var_array_buffer.Unmap(); + return value; + } + case PP_VARTYPE_RESOURCE: + // There is no valid conversion from PP_VARTYPE_RESOURCE to a base::Value + // type. This should not be called to convert this type. + NOTREACHED(); + return base::Value(); + } +} + +} // namespace chrome_pdf diff --git a/chromium/pdf/ppapi_migration/value_conversions.h b/chromium/pdf/ppapi_migration/value_conversions.h index 3b93df5a952..edfea999812 100644 --- a/chromium/pdf/ppapi_migration/value_conversions.h +++ b/chromium/pdf/ppapi_migration/value_conversions.h @@ -16,7 +16,8 @@ class Var; namespace chrome_pdf { pp::Var VarFromValue(const base::Value& value); +base::Value ValueFromVar(const pp::Var& var); } // namespace chrome_pdf -#endif // PDF_PPAPI_MIGRATION_VALUE_CONVERSIONS_H_
\ No newline at end of file +#endif // PDF_PPAPI_MIGRATION_VALUE_CONVERSIONS_H_ diff --git a/chromium/pdf/preview_mode_client.cc b/chromium/pdf/preview_mode_client.cc index 41dd568e769..b4511fe8331 100644 --- a/chromium/pdf/preview_mode_client.cc +++ b/chromium/pdf/preview_mode_client.cc @@ -6,12 +6,14 @@ #include <stdint.h> +#include <memory> #include <string> #include <utility> #include "base/callback.h" #include "base/notreached.h" #include "pdf/document_layout.h" +#include "pdf/ppapi_migration/url_loader.h" namespace chrome_pdf { @@ -22,7 +24,7 @@ void PreviewModeClient::ProposeDocumentLayout(const DocumentLayout& layout) { // occurs if and only if loading a non-PDF document with more than 1 page. } -void PreviewModeClient::Invalidate(const pp::Rect& rect) { +void PreviewModeClient::Invalidate(const gfx::Rect& rect) { NOTREACHED(); } @@ -57,7 +59,7 @@ void PreviewModeClient::UpdateCursor(PP_CursorType_Dev cursor) { } void PreviewModeClient::UpdateTickMarks( - const std::vector<pp::Rect>& tickmarks) { + const std::vector<gfx::Rect>& tickmarks) { NOTREACHED(); } @@ -114,9 +116,9 @@ void PreviewModeClient::SubmitForm(const std::string& url, NOTREACHED(); } -pp::URLLoader PreviewModeClient::CreateURLLoader() { +std::unique_ptr<UrlLoader> PreviewModeClient::CreateUrlLoader() { NOTREACHED(); - return pp::URLLoader(); + return nullptr; } std::vector<PDFEngine::Client::SearchStringResult> diff --git a/chromium/pdf/preview_mode_client.h b/chromium/pdf/preview_mode_client.h index 5c78f666be7..4b9c2e62508 100644 --- a/chromium/pdf/preview_mode_client.h +++ b/chromium/pdf/preview_mode_client.h @@ -14,6 +14,7 @@ #include "pdf/pdf_engine.h" namespace gfx { +class Rect; class Vector2d; } // namespace gfx @@ -33,7 +34,7 @@ class PreviewModeClient : public PDFEngine::Client { // PDFEngine::Client implementation. void ProposeDocumentLayout(const DocumentLayout& layout) override; - void Invalidate(const pp::Rect& rect) override; + void Invalidate(const gfx::Rect& rect) override; void DidScroll(const gfx::Vector2d& offset) override; void ScrollToX(int x_in_screen_coords) override; void ScrollToY(int y_in_screen_coords, bool compensate_for_toolbar) override; @@ -42,7 +43,7 @@ class PreviewModeClient : public PDFEngine::Client { void NavigateTo(const std::string& url, WindowOpenDisposition disposition) override; void UpdateCursor(PP_CursorType_Dev cursor) override; - void UpdateTickMarks(const std::vector<pp::Rect>& tickmarks) 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 GetDocumentPassword( @@ -61,7 +62,7 @@ class PreviewModeClient : public PDFEngine::Client { void SubmitForm(const std::string& url, const void* data, int length) override; - pp::URLLoader CreateURLLoader() override; + std::unique_ptr<UrlLoader> CreateUrlLoader() override; std::vector<SearchStringResult> SearchString(const base::char16* string, const base::char16* term, bool case_sensitive) override; diff --git a/chromium/pdf/thumbnail.cc b/chromium/pdf/thumbnail.cc new file mode 100644 index 00000000000..2419e92c0be --- /dev/null +++ b/chromium/pdf/thumbnail.cc @@ -0,0 +1,125 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "pdf/thumbnail.h" + +#include <algorithm> +#include <cmath> + +#include "base/check.h" +#include "base/check_op.h" +#include "base/numerics/ranges.h" +#include "base/numerics/safe_math.h" +#include "third_party/skia/include/core/SkBitmap.h" +#include "third_party/skia/include/core/SkImageInfo.h" +#include "ui/gfx/geometry/size.h" + +namespace chrome_pdf { + +namespace { + +constexpr float kMinDevicePixelRatio = 0.25; +constexpr float kMaxDevicePixelRatio = 2; + +constexpr int kImageColorChannels = 4; + +// TODO(crbug.com/702993): Reevaluate the thumbnail size cap when the PDF +// component migrates off of PPAPI. +// The maximum thumbnail area is essentially arbitrary, but the value was chosen +// considering the fact that when sending array buffers through PPAPI, if the +// size of the data is over 256KiB, it gets sent using shared memory instead of +// IPC. Thumbnail sizes are capped at 255KiB to avoid the 256KiB threshold for +// images and their metadata, such as size. +constexpr int kMaxThumbnailPixels = 255 * 1024 / kImageColorChannels; + +// Maximum CSS dimensions are set to match UX specifications. +// These constants should be kept in sync with `PORTRAIT_WIDTH` and +// `LANDSCAPE_WIDTH` in +// chrome/browser/resources/pdf/elements/viewer-thumbnail.js. +constexpr int kMaxWidthPortraitPx = 108; +constexpr int kMaxWidthLandscapePx = 140; + +// PDF page size limits in default user space units, as defined by PDF 1.7 Annex +// C.2, "Architectural limits". +constexpr int kPdfPageMinDimension = 3; +constexpr int kPdfPageMaxDimension = 14400; +constexpr int kPdfMaxAspectRatio = kPdfPageMaxDimension / kPdfPageMinDimension; + +// Limit the proportions within PDF limits to handle pathological PDF pages. +gfx::Size LimitAspectRatio(gfx::Size page_size) { + // Bump up any lengths of 0 to 1. + page_size.SetToMax(gfx::Size(1, 1)); + + if (page_size.height() / page_size.width() > kPdfMaxAspectRatio) + return gfx::Size(kPdfPageMinDimension, kPdfPageMaxDimension); + if (page_size.width() / page_size.height() > kPdfMaxAspectRatio) + return gfx::Size(kPdfPageMaxDimension, kPdfPageMinDimension); + + return page_size; +} + +// Calculate the size of a thumbnail image in device pixels using |page_size| in +// any units and |device_pixel_ratio|. +gfx::Size CalculateBestFitSize(const gfx::Size& page_size, + float device_pixel_ratio) { + gfx::Size safe_page_size = LimitAspectRatio(page_size); + + // Return the larger of the unrotated and rotated sizes to over-sample the PDF + // page so that the thumbnail looks good in different orientations. + float scale_portrait = + static_cast<float>(kMaxWidthPortraitPx) / + std::min(safe_page_size.width(), safe_page_size.height()); + float scale_landscape = + static_cast<float>(kMaxWidthLandscapePx) / + std::max(safe_page_size.width(), safe_page_size.height()); + float scale = std::max(scale_portrait, scale_landscape) * device_pixel_ratio; + + // Using gfx::ScaleToFlooredSize() is fine because `scale` will not yield an + // empty size unless `device_pixel_ratio` is very small (close to 0). + // However, `device_pixel_ratio` support is limited to between 0.25 and 2. + gfx::Size scaled_size = gfx::ScaleToFlooredSize(safe_page_size, scale); + if (scaled_size.GetCheckedArea().ValueOrDefault(kMaxThumbnailPixels + 1) > + kMaxThumbnailPixels) { + // Recalculate `scale` to accommodate pixel size limit such that: + // (scale * safe_page_size.width()) * (scale * safe_page_size.height()) == + // kMaxThumbnailPixels; + scale = std::sqrt(static_cast<float>(kMaxThumbnailPixels) / + safe_page_size.width() / safe_page_size.height()); + return gfx::ScaleToFlooredSize(safe_page_size, scale); + } + + return scaled_size; +} + +} // namespace + +Thumbnail::Thumbnail() = default; + +Thumbnail::Thumbnail(const gfx::Size& page_size, float device_pixel_ratio) { + DCHECK_GE(device_pixel_ratio, kMinDevicePixelRatio); + DCHECK_LE(device_pixel_ratio, kMaxDevicePixelRatio); + device_pixel_ratio_ = base::ClampToRange( + device_pixel_ratio, kMinDevicePixelRatio, kMaxDevicePixelRatio); + + const gfx::Size thumbnail_size_device_pixels = + CalculateBestFitSize(page_size, device_pixel_ratio_); + + // Note that <canvas> can only hold data in RGBA format. It is the + // responsibility of the thumbnail's renderer to fill `bitmap_` with RGBA + // data. + const SkImageInfo info = + SkImageInfo::Make(thumbnail_size_device_pixels.width(), + thumbnail_size_device_pixels.height(), + kRGBA_8888_SkColorType, kPremul_SkAlphaType); + bool success = bitmap_.tryAllocPixels(info, info.minRowBytes()); + DCHECK(success); +} + +Thumbnail::Thumbnail(Thumbnail&& other) = default; + +Thumbnail& Thumbnail::operator=(Thumbnail&& other) = default; + +Thumbnail::~Thumbnail() = default; + +} // namespace chrome_pdf diff --git a/chromium/pdf/thumbnail.h b/chromium/pdf/thumbnail.h new file mode 100644 index 00000000000..d62a56a5091 --- /dev/null +++ b/chromium/pdf/thumbnail.h @@ -0,0 +1,41 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PDF_THUMBNAIL_H_ +#define PDF_THUMBNAIL_H_ + +#include "third_party/skia/include/core/SkBitmap.h" + +namespace gfx { +class Size; +} // namespace gfx + +namespace chrome_pdf { + +class Thumbnail final { + public: + Thumbnail(); + Thumbnail(const gfx::Size& page_size, float device_pixel_ratio); + Thumbnail(Thumbnail&& other); + Thumbnail& operator=(Thumbnail&& other); + ~Thumbnail(); + + SkBitmap& bitmap() { return bitmap_; } + + float device_pixel_ratio() const { return device_pixel_ratio_; } + + private: + // Raw image data of the thumbnail. + SkBitmap bitmap_; + + // Intended resolution of the thumbnail image. The dimensions of `bitmap_` + // are the dimensions of the thumbnail in CSS pixels multiplied by + // `device_pixel_ratio_`. + // Only values between 0.25 and 2 are supported. + float device_pixel_ratio_ = 1; +}; + +} // namespace chrome_pdf + +#endif // PDF_THUMBNAIL_H_ diff --git a/chromium/pdf/thumbnail_unittest.cc b/chromium/pdf/thumbnail_unittest.cc new file mode 100644 index 00000000000..03a8ef286e5 --- /dev/null +++ b/chromium/pdf/thumbnail_unittest.cc @@ -0,0 +1,83 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "pdf/thumbnail.h" + +#include "testing/gtest/include/gtest/gtest.h" +#include "ui/gfx/geometry/size.h" + +namespace chrome_pdf { + +namespace { + +constexpr float kDeviceToPixelLow = 1; +constexpr float kDeviceToPixelHigh = 2; + +struct BestFitSizeParams { + float device_pixel_ratio; + gfx::Size page_size; + gfx::Size expected_thumbnail_size; +}; + +void TestBestFitSize(const BestFitSizeParams& params) { + Thumbnail thumbnail(params.page_size, params.device_pixel_ratio); + EXPECT_EQ(gfx::Size(thumbnail.bitmap().width(), thumbnail.bitmap().height()), + params.expected_thumbnail_size) + << "Failed for page of size of " << params.page_size.ToString() + << " and device to pixel ratio of " << params.device_pixel_ratio; +} + +TEST(ThumbnailTest, CalculateBestFitSizeNormal) { + static constexpr BestFitSizeParams kBestFitSizeTestParams[] = { + {kDeviceToPixelLow, {612, 792}, {108, 140}}, // ANSI Letter + {kDeviceToPixelLow, {595, 842}, {108, 152}}, // ISO 216 A4 + {kDeviceToPixelLow, {200, 200}, {140, 140}}, // Square + {kDeviceToPixelLow, {1000, 200}, {540, 108}}, // Wide + {kDeviceToPixelLow, {200, 1000}, {108, 540}}, // Tall + {kDeviceToPixelLow, {1500, 50}, {1399, 46}}, // Super wide + {kDeviceToPixelLow, {50, 1500}, {46, 1399}}, // Super tall + {kDeviceToPixelHigh, {612, 792}, {216, 280}}, // ANSI Letter + {kDeviceToPixelHigh, {595, 842}, {214, 303}}, // ISO 216 A4 + {kDeviceToPixelHigh, {200, 200}, {255, 255}}, // Square + {kDeviceToPixelHigh, {1000, 200}, {571, 114}}, // Wide + {kDeviceToPixelHigh, {200, 1000}, {114, 571}}, // Tall + {kDeviceToPixelHigh, {1500, 50}, {1399, 46}}, // Super wide + {kDeviceToPixelHigh, {50, 1500}, {46, 1399}}, // Super tall + }; + + for (const auto& params : kBestFitSizeTestParams) + TestBestFitSize(params); +} + +TEST(ThumbnailTest, CalculateBestFitSizeLargeAspectRatio) { + static constexpr BestFitSizeParams kBestFitSizeTestParams[] = { + {kDeviceToPixelLow, {14400, 3}, {17701, 3}}, // PDF 1.7 widest + {kDeviceToPixelLow, {3, 14400}, {3, 17701}}, // PDF 1.7 tallest + {kDeviceToPixelLow, {0, 0}, {140, 140}}, // Empty + {kDeviceToPixelLow, {9999999, 1}, {17701, 3}}, // Very wide + {kDeviceToPixelLow, {1, 9999999}, {3, 17701}}, // Very tall + {kDeviceToPixelHigh, {14400, 3}, {17701, 3}}, // PDF 1.7 widest + {kDeviceToPixelHigh, {3, 14400}, {3, 17701}}, // PDF 1.7 tallest + {kDeviceToPixelHigh, {0, 0}, {255, 255}}, // Empty + {kDeviceToPixelHigh, {9999999, 1}, {17701, 3}}, // Very wide + {kDeviceToPixelHigh, {1, 9999999}, {3, 17701}}, // Very tall + }; + + for (const auto& params : kBestFitSizeTestParams) + TestBestFitSize(params); +} + +TEST(ThumbnailTest, CalculateBestFitSizeNoOverflow) { + static constexpr BestFitSizeParams kBestFitSizeTestParams[] = { + {kDeviceToPixelLow, {9999999, 9999999}, {140, 140}}, // Very large + {kDeviceToPixelHigh, {9999999, 9999999}, {255, 255}}, // Very large + }; + + for (const auto& params : kBestFitSizeTestParams) + TestBestFitSize(params); +} + +} // namespace + +} // namespace chrome_pdf diff --git a/chromium/pdf/url_loader_wrapper.h b/chromium/pdf/url_loader_wrapper.h index e594acfc350..58cc94ab4ec 100644 --- a/chromium/pdf/url_loader_wrapper.h +++ b/chromium/pdf/url_loader_wrapper.h @@ -58,14 +58,6 @@ class URLLoaderWrapper { virtual void ReadResponseBody(char* buffer, int buffer_size, ResultCallback callback) = 0; - - // Returns the current download progress. - // Progress only refers to the response body and does not include the headers. - // If false, progress is unknown, bytes_received/total_bytes_to_be_received - // will be undefined. - virtual bool GetDownloadProgress( - int64_t* bytes_received, - int64_t* total_bytes_to_be_received) const = 0; }; } // namespace chrome_pdf diff --git a/chromium/pdf/url_loader_wrapper_impl.cc b/chromium/pdf/url_loader_wrapper_impl.cc index 20ee17a77ad..5396b639fc8 100644 --- a/chromium/pdf/url_loader_wrapper_impl.cc +++ b/chromium/pdf/url_loader_wrapper_impl.cc @@ -4,20 +4,24 @@ #include "pdf/url_loader_wrapper_impl.h" +#include <stddef.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> + #include <memory> +#include <string> #include <utility> #include "base/bind.h" #include "base/callback.h" #include "base/check_op.h" +#include "base/containers/span.h" #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" #include "net/http/http_util.h" -#include "ppapi/c/pp_errors.h" -#include "ppapi/cpp/completion_callback.h" -#include "ppapi/cpp/logging.h" -#include "ppapi/cpp/url_request_info.h" -#include "ppapi/cpp/url_response_info.h" +#include "pdf/ppapi_migration/url_loader.h" +#include "ui/gfx/range/range.h" namespace chrome_pdf { @@ -26,25 +30,22 @@ namespace { // We should read with delay to prevent block UI thread, and reduce CPU usage. constexpr base::TimeDelta kReadDelayMs = base::TimeDelta::FromMilliseconds(2); -pp::URLRequestInfo MakeRangeRequest(pp::Instance* plugin_instance, - const std::string& url, - const std::string& referrer_url, - uint32_t position, - uint32_t size) { - pp::URLRequestInfo request(plugin_instance); - request.SetURL(url); - request.SetMethod("GET"); - request.SetFollowRedirects(false); - request.SetCustomReferrerURL(referrer_url); +UrlRequest MakeRangeRequest(const std::string& url, + const std::string& referrer_url, + uint32_t position, + uint32_t size) { + UrlRequest request; + request.url = url; + request.method = "GET"; + request.ignore_redirects = true; + request.custom_referrer_url = referrer_url; // According to rfc2616, byte range specifies position of the first and last // bytes in the requested range inclusively. Therefore we should subtract 1 // from the position + size, to get index of the last byte that needs to be // downloaded. - std::string str_header = + request.headers = base::StringPrintf("Range: bytes=%d-%d", position, position + size - 1); - pp::Var header(str_header.c_str()); - request.SetHeaders(header); return request; } @@ -100,9 +101,9 @@ bool IsDoubleEndLineAtEnd(const char* buffer, int size) { } // namespace -URLLoaderWrapperImpl::URLLoaderWrapperImpl(pp::Instance* plugin_instance, - const pp::URLLoader& url_loader) - : plugin_instance_(plugin_instance), url_loader_(url_loader) { +URLLoaderWrapperImpl::URLLoaderWrapperImpl( + std::unique_ptr<UrlLoader> url_loader) + : url_loader_(std::move(url_loader)) { SetHeadersFromLoader(); } @@ -130,7 +131,7 @@ std::string URLLoaderWrapperImpl::GetContentDisposition() const { } int URLLoaderWrapperImpl::GetStatusCode() const { - return url_loader_.GetResponseInfo().GetStatusCode(); + return url_loader_->response().status_code; } bool URLLoaderWrapperImpl::IsMultipart() const { @@ -143,15 +144,8 @@ bool URLLoaderWrapperImpl::GetByteRangeStart(int* start) const { return byte_range_.IsValid(); } -bool URLLoaderWrapperImpl::GetDownloadProgress( - int64_t* bytes_received, - int64_t* total_bytes_to_be_received) const { - return url_loader_.GetDownloadProgress(bytes_received, - total_bytes_to_be_received); -} - void URLLoaderWrapperImpl::Close() { - url_loader_.Close(); + url_loader_->Close(); read_starter_.Stop(); } @@ -160,14 +154,10 @@ void URLLoaderWrapperImpl::OpenRange(const std::string& url, uint32_t position, uint32_t size, ResultCallback callback) { - pp::CompletionCallback cc = PPCompletionCallbackFromResultCallback( + url_loader_->Open( + MakeRangeRequest(url, referrer_url, position, size), base::BindOnce(&URLLoaderWrapperImpl::DidOpen, weak_factory_.GetWeakPtr(), std::move(callback))); - int rv = url_loader_.Open( - MakeRangeRequest(plugin_instance_, url, referrer_url, position, size), - cc); - if (rv != PP_OK_COMPLETIONPENDING) - cc.Run(rv); } void URLLoaderWrapperImpl::ReadResponseBody(char* buffer, @@ -182,13 +172,10 @@ void URLLoaderWrapperImpl::ReadResponseBody(char* buffer, } void URLLoaderWrapperImpl::ReadResponseBodyImpl(ResultCallback callback) { - pp::CompletionCallback cc = PPCompletionCallbackFromResultCallback( + url_loader_->ReadResponseBody( + base::make_span(buffer_, buffer_size_), base::BindOnce(&URLLoaderWrapperImpl::DidRead, weak_factory_.GetWeakPtr(), std::move(callback))); - int rv = url_loader_.ReadResponseBody(buffer_, buffer_size_, cc); - if (rv != PP_OK_COMPLETIONPENDING) { - cc.Run(rv); - } } void URLLoaderWrapperImpl::SetResponseHeaders( @@ -300,10 +287,7 @@ void URLLoaderWrapperImpl::DidRead(ResultCallback callback, int32_t result) { } void URLLoaderWrapperImpl::SetHeadersFromLoader() { - pp::URLResponseInfo response = url_loader_.GetResponseInfo(); - pp::Var headers_var = response.GetHeaders(); - - SetResponseHeaders(headers_var.is_string() ? headers_var.AsString() : ""); + SetResponseHeaders(url_loader_->response().headers); } } // namespace chrome_pdf diff --git a/chromium/pdf/url_loader_wrapper_impl.h b/chromium/pdf/url_loader_wrapper_impl.h index 1de27e6f9b4..22f3a413789 100644 --- a/chromium/pdf/url_loader_wrapper_impl.h +++ b/chromium/pdf/url_loader_wrapper_impl.h @@ -14,19 +14,15 @@ #include "base/timer/timer.h" #include "pdf/ppapi_migration/callback.h" #include "pdf/url_loader_wrapper.h" -#include "ppapi/cpp/url_loader.h" #include "ui/gfx/range/range.h" -namespace pp { -class Instance; -} - namespace chrome_pdf { +class UrlLoader; + class URLLoaderWrapperImpl : public URLLoaderWrapper { public: - URLLoaderWrapperImpl(pp::Instance* plugin_instance, - const pp::URLLoader& url_loader); + explicit URLLoaderWrapperImpl(std::unique_ptr<UrlLoader> url_loader); URLLoaderWrapperImpl(const URLLoaderWrapperImpl&) = delete; URLLoaderWrapperImpl& operator=(const URLLoaderWrapperImpl&) = delete; ~URLLoaderWrapperImpl() override; @@ -40,8 +36,6 @@ class URLLoaderWrapperImpl : public URLLoaderWrapper { int GetStatusCode() const override; bool IsMultipart() const override; bool GetByteRangeStart(int* start) const override; - bool GetDownloadProgress(int64_t* bytes_received, - int64_t* total_bytes_to_be_received) const override; void Close() override; void OpenRange(const std::string& url, const std::string& referrer_url, @@ -62,8 +56,7 @@ class URLLoaderWrapperImpl : public URLLoaderWrapper { void ReadResponseBodyImpl(ResultCallback callback); - pp::Instance* const plugin_instance_; - pp::URLLoader url_loader_; + std::unique_ptr<UrlLoader> url_loader_; std::string response_headers_; int content_length_ = -1; |