123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869 |
- // Copyright 2019 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "pdf/pdfium/pdfium_page.h"
- #include <utility>
- #include <vector>
- #include "base/check.h"
- #include "base/files/file_path.h"
- #include "base/strings/string_util.h"
- #include "base/strings/stringprintf.h"
- #include "base/test/scoped_feature_list.h"
- #include "pdf/accessibility_structs.h"
- #include "pdf/pdfium/pdfium_engine.h"
- #include "pdf/pdfium/pdfium_test_base.h"
- #include "pdf/test/test_client.h"
- #include "pdf/test/test_helpers.h"
- #include "pdf/ui/thumbnail.h"
- #include "testing/gtest/include/gtest/gtest.h"
- #include "third_party/abseil-cpp/absl/types/optional.h"
- #include "third_party/pdfium/public/fpdf_formfill.h"
- #include "third_party/skia/include/core/SkImage.h"
- #include "third_party/skia/include/core/SkImageInfo.h"
- #include "third_party/skia/include/core/SkPixmap.h"
- #include "third_party/skia/include/core/SkRefCnt.h"
- #include "ui/accessibility/accessibility_features.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/skia_conversions.h"
- #include "ui/gfx/geometry/test/geometry_util.h"
- #include "ui/gfx/range/range.h"
- namespace chrome_pdf {
- namespace {
- TEST(PDFiumPageHelperTest, ToPDFiumRotation) {
- EXPECT_EQ(ToPDFiumRotation(PageOrientation::kOriginal), 0);
- EXPECT_EQ(ToPDFiumRotation(PageOrientation::kClockwise90), 1);
- EXPECT_EQ(ToPDFiumRotation(PageOrientation::kClockwise180), 2);
- EXPECT_EQ(ToPDFiumRotation(PageOrientation::kClockwise270), 3);
- }
- void CompareTextRuns(const AccessibilityTextRunInfo& expected_text_run,
- const AccessibilityTextRunInfo& actual_text_run) {
- EXPECT_EQ(expected_text_run.len, actual_text_run.len);
- EXPECT_RECTF_EQ(expected_text_run.bounds, actual_text_run.bounds);
- EXPECT_EQ(expected_text_run.direction, actual_text_run.direction);
- const AccessibilityTextStyleInfo& expected_style = expected_text_run.style;
- const AccessibilityTextStyleInfo& actual_style = actual_text_run.style;
- EXPECT_EQ(expected_style.font_name, actual_style.font_name);
- EXPECT_EQ(expected_style.font_weight, actual_style.font_weight);
- EXPECT_EQ(expected_style.render_mode, actual_style.render_mode);
- EXPECT_FLOAT_EQ(expected_style.font_size, actual_style.font_size);
- EXPECT_EQ(expected_style.fill_color, actual_style.fill_color);
- EXPECT_EQ(expected_style.stroke_color, actual_style.stroke_color);
- EXPECT_EQ(expected_style.is_italic, actual_style.is_italic);
- EXPECT_EQ(expected_style.is_bold, actual_style.is_bold);
- }
- template <typename T>
- void PopulateTextObjects(const std::vector<gfx::Range>& ranges,
- std::vector<T>* text_objects) {
- text_objects->resize(ranges.size());
- for (size_t i = 0; i < ranges.size(); ++i) {
- (*text_objects)[i].start_char_index = ranges[i].start();
- (*text_objects)[i].char_count = ranges[i].end() - ranges[i].start();
- }
- }
- // Returns the page size for a `PDFiumPage`. The caller must make sure that
- // `pdfium_page` is available.
- gfx::SizeF GetPageSizeHelper(PDFiumPage& pdfium_page) {
- FPDF_PAGE page = pdfium_page.GetPage();
- return gfx::SizeF(FPDF_GetPageWidthF(page), FPDF_GetPageHeightF(page));
- }
- 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);
- return base::FilePath(FILE_PATH_LITERAL("thumbnail"))
- .AppendASCII(file_dir)
- .AppendASCII(file_name);
- }
- } // namespace
- using PDFiumPageTest = PDFiumTestBase;
- TEST_F(PDFiumPageTest, Constructor) {
- PDFiumPage page(/*engine=*/nullptr, 2);
- EXPECT_EQ(page.index(), 2);
- EXPECT_TRUE(page.rect().IsEmpty());
- EXPECT_FALSE(page.available());
- }
- TEST_F(PDFiumPageTest, IsCharInPageBounds) {
- TestClient client;
- std::unique_ptr<PDFiumEngine> engine =
- InitializeEngine(&client, FILE_PATH_LITERAL("hello_world_cropped.pdf"));
- ASSERT_TRUE(engine);
- PDFiumPage page(engine.get(), 0);
- EXPECT_FALSE(page.available());
- EXPECT_EQ(page.GetCharCount(), 0);
- page.MarkAvailable();
- EXPECT_TRUE(page.available());
- EXPECT_EQ(page.GetCharCount(), 30);
- const gfx::RectF page_bounds = page.GetCroppedRect();
- EXPECT_EQ(page_bounds, gfx::RectF(193.33333f, 129.33333f));
- EXPECT_EQ(page.GetCharAtIndex(0), 'H');
- EXPECT_FALSE(page.IsCharInPageBounds(0, page_bounds));
- EXPECT_EQ(page.GetCharAtIndex(12), '!');
- EXPECT_TRUE(page.IsCharInPageBounds(12, page_bounds));
- EXPECT_EQ(page.GetCharAtIndex(13), '\r');
- EXPECT_TRUE(page.IsCharInPageBounds(13, page_bounds));
- EXPECT_EQ(page.GetCharAtIndex(14), '\n');
- EXPECT_TRUE(page.IsCharInPageBounds(14, page_bounds));
- EXPECT_EQ(page.GetCharAtIndex(15), 'G');
- EXPECT_FALSE(page.IsCharInPageBounds(15, page_bounds));
- EXPECT_EQ(page.GetCharAtIndex(29), '!');
- EXPECT_FALSE(page.IsCharInPageBounds(29, page_bounds));
- }
- class PDFiumPageLinkTest : public PDFiumTestBase {
- public:
- PDFiumPageLinkTest() = default;
- PDFiumPageLinkTest(const PDFiumPageLinkTest&) = delete;
- PDFiumPageLinkTest& operator=(const PDFiumPageLinkTest&) = delete;
- ~PDFiumPageLinkTest() override = default;
- const std::vector<PDFiumPage::Link>& GetLinks(PDFiumEngine& engine,
- int page_index) {
- PDFiumPage& page = GetPDFiumPageForTest(engine, page_index);
- page.CalculateLinks();
- return page.links_;
- }
- };
- TEST_F(PDFiumPageLinkTest, LinkGeneration) {
- TestClient client;
- std::unique_ptr<PDFiumEngine> engine =
- InitializeEngine(&client, FILE_PATH_LITERAL("weblinks.pdf"));
- ASSERT_TRUE(engine);
- ASSERT_EQ(1, engine->GetNumberOfPages());
- bool using_test_fonts = UsingTestFonts();
- const std::vector<PDFiumPage::Link>& links = GetLinks(*engine, 0);
- ASSERT_EQ(3u, links.size());
- const PDFiumPage::Link& link = links[0];
- EXPECT_EQ("http://yahoo.com", link.target.url);
- EXPECT_EQ(7, link.start_char_index);
- EXPECT_EQ(16, link.char_count);
- ASSERT_EQ(1u, link.bounding_rects.size());
- if (using_test_fonts) {
- EXPECT_EQ(gfx::Rect(75, 192, 110, 15), link.bounding_rects[0]);
- } else {
- EXPECT_EQ(gfx::Rect(75, 191, 110, 16), link.bounding_rects[0]);
- }
- const PDFiumPage::Link& second_link = links[1];
- EXPECT_EQ("http://bing.com", second_link.target.url);
- EXPECT_EQ(52, second_link.start_char_index);
- EXPECT_EQ(15, second_link.char_count);
- ASSERT_EQ(1u, second_link.bounding_rects.size());
- if (using_test_fonts) {
- EXPECT_EQ(gfx::Rect(131, 120, 138, 22), second_link.bounding_rects[0]);
- } else {
- EXPECT_EQ(gfx::Rect(131, 121, 138, 20), second_link.bounding_rects[0]);
- }
- const PDFiumPage::Link& third_link = links[2];
- EXPECT_EQ("http://google.com", third_link.target.url);
- EXPECT_EQ(92, third_link.start_char_index);
- EXPECT_EQ(17, third_link.char_count);
- ASSERT_EQ(1u, third_link.bounding_rects.size());
- EXPECT_EQ(gfx::Rect(82, 67, 161, 21), third_link.bounding_rects[0]);
- }
- TEST_F(PDFiumPageLinkTest, AnnotLinkGeneration) {
- struct ExpectedLink {
- int32_t start_char_index;
- int32_t char_count;
- std::vector<gfx::Rect> bounding_rects;
- std::string url;
- int page;
- float y_in_pixels;
- };
- static ExpectedLink expected_links[] = {
- {144, 38, {{99, 436, 236, 13}}, "https://pdfium.googlesource.com/pdfium"},
- {27, 38, {{112, 215, 617, 28}}, "", 1, 89.333336},
- {65, 27, {{93, 334, 174, 21}}, "https://www.adobe.com"},
- {253,
- 18,
- {{242, 455, 1, 18}, {242, 472, 1, 15}},
- "https://cs.chromium.org"},
- {-1, 0, {{58, 926, 28, 27}}, "https://www.google.com"}};
- if (UsingTestFonts()) {
- expected_links[0].bounding_rects[0] = {99, 436, 236, 14};
- }
- static constexpr size_t kExpectedLinkCount = std::size(expected_links);
- TestClient client;
- std::unique_ptr<PDFiumEngine> engine =
- InitializeEngine(&client, FILE_PATH_LITERAL("link_annots.pdf"));
- ASSERT_TRUE(engine);
- ASSERT_EQ(2, engine->GetNumberOfPages());
- const std::vector<PDFiumPage::Link>& links = GetLinks(*engine, 0);
- ASSERT_EQ(kExpectedLinkCount, links.size());
- for (size_t i = 0; i < kExpectedLinkCount; ++i) {
- const PDFiumPage::Link& actual_current_link = links[i];
- const ExpectedLink& expected_current_link = expected_links[i];
- EXPECT_EQ(expected_current_link.start_char_index,
- actual_current_link.start_char_index);
- EXPECT_EQ(expected_current_link.char_count, actual_current_link.char_count);
- 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) {
- 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()) {
- EXPECT_EQ(expected_current_link.page, actual_current_link.target.page);
- ASSERT_TRUE(actual_current_link.target.y_in_pixels.has_value());
- EXPECT_FLOAT_EQ(expected_current_link.y_in_pixels,
- actual_current_link.target.y_in_pixels.value());
- }
- }
- }
- TEST_F(PDFiumPageLinkTest, GetLinkTarget) {
- TestClient client;
- std::unique_ptr<PDFiumEngine> engine = InitializeEngine(
- &client, FILE_PATH_LITERAL("in_doc_link_with_various_page_sizes.pdf"));
- ASSERT_EQ(3, engine->GetNumberOfPages());
- const std::vector<PDFiumPage::Link>& links = GetLinks(*engine, 0);
- ASSERT_EQ(1u, links.size());
- // Get the destination link that exists in the first page.
- PDFiumPage& first_page = GetPDFiumPageForTest(*engine, 0);
- FPDF_LINK link = FPDFLink_GetLinkAtPoint(first_page.GetPage(), 70, 740);
- ASSERT_TRUE(link);
- FPDF_DEST dest_link = FPDFLink_GetDest(engine->doc(), link);
- ASSERT_TRUE(dest_link);
- PDFiumPage::LinkTarget target;
- PDFiumPage::Area area = first_page.GetLinkTarget(link, &target);
- EXPECT_EQ(PDFiumPage::Area::DOCLINK_AREA, area);
- EXPECT_EQ(1, target.page);
- // Make sure the target page's size is different from the first page's. This
- // guarantees that the in-screen coordinates are calculated based on the
- // target page's dimension.
- PDFiumPage& target_page = GetPDFiumPageForTest(*engine, target.page);
- ASSERT_TRUE(target_page.available());
- ASSERT_TRUE(first_page.available());
- EXPECT_NE(GetPageSizeHelper(first_page), GetPageSizeHelper(target_page));
- EXPECT_FLOAT_EQ(74.666664f, target.x_in_pixels.value());
- EXPECT_FLOAT_EQ(120.f, target.y_in_pixels.value());
- EXPECT_FALSE(target.zoom);
- }
- using PDFiumPageImageTest = PDFiumTestBase;
- TEST_F(PDFiumPageImageTest, CalculateImages) {
- TestClient client;
- std::unique_ptr<PDFiumEngine> engine =
- InitializeEngine(&client, FILE_PATH_LITERAL("image_alt_text.pdf"));
- ASSERT_TRUE(engine);
- ASSERT_EQ(1, engine->GetNumberOfPages());
- PDFiumPage& page = GetPDFiumPageForTest(*engine, 0);
- page.CalculateImages();
- ASSERT_EQ(3u, page.images_.size());
- EXPECT_EQ(gfx::Rect(380, 78, 67, 68), page.images_[0].bounding_rect);
- EXPECT_EQ("Image 1", page.images_[0].alt_text);
- EXPECT_EQ(gfx::Rect(380, 385, 27, 28), page.images_[1].bounding_rect);
- EXPECT_EQ("Image 2", page.images_[1].alt_text);
- EXPECT_EQ(gfx::Rect(380, 678, 1, 1), page.images_[2].bounding_rect);
- EXPECT_EQ("Image 3", page.images_[2].alt_text);
- }
- TEST_F(PDFiumPageImageTest, ImageAltText) {
- TestClient client;
- std::unique_ptr<PDFiumEngine> engine =
- InitializeEngine(&client, FILE_PATH_LITERAL("text_with_image.pdf"));
- ASSERT_TRUE(engine);
- ASSERT_EQ(1, engine->GetNumberOfPages());
- PDFiumPage& page = GetPDFiumPageForTest(*engine, 0);
- page.CalculateImages();
- ASSERT_EQ(3u, page.images_.size());
- EXPECT_EQ(gfx::Rect(380, 78, 67, 68), page.images_[0].bounding_rect);
- EXPECT_EQ("Image 1", page.images_[0].alt_text);
- EXPECT_EQ(gfx::Rect(380, 385, 27, 28), page.images_[1].bounding_rect);
- EXPECT_EQ("", page.images_[1].alt_text);
- EXPECT_EQ(gfx::Rect(380, 678, 1, 1), page.images_[2].bounding_rect);
- EXPECT_EQ("", page.images_[2].alt_text);
- }
- class PDFiumPageImageDataTest : public PDFiumPageImageTest {
- public:
- PDFiumPageImageDataTest() : enable_pdf_ocr_({features::kPdfOcr}) {}
- PDFiumPageImageDataTest(const PDFiumPageImageDataTest&) = delete;
- PDFiumPageImageDataTest& operator=(const PDFiumPageImageDataTest&) = delete;
- ~PDFiumPageImageDataTest() override = default;
- private:
- base::test::ScopedFeatureList enable_pdf_ocr_;
- };
- TEST_F(PDFiumPageImageDataTest, ImageData) {
- TestClient client;
- std::unique_ptr<PDFiumEngine> engine =
- InitializeEngine(&client, FILE_PATH_LITERAL("text_with_image.pdf"));
- ASSERT_TRUE(engine);
- ASSERT_EQ(1, engine->GetNumberOfPages());
- PDFiumPage& page = GetPDFiumPageForTest(*engine, 0);
- page.CalculateImages();
- ASSERT_EQ(3u, page.images_.size());
- ASSERT_FALSE(page.images_[0].alt_text.empty());
- EXPECT_TRUE(page.images_[0].image_data.drawsNothing());
- EXPECT_EQ(page.images_[0].image_data.width(), 0);
- EXPECT_EQ(page.images_[0].image_data.height(), 0);
- ASSERT_TRUE(page.images_[2].alt_text.empty());
- EXPECT_EQ(page.images_[1].image_data.width(), 20);
- EXPECT_EQ(page.images_[1].image_data.height(), 20);
- }
- using PDFiumPageTextTest = PDFiumTestBase;
- TEST_F(PDFiumPageTextTest, TextRunBounds) {
- TestClient client;
- std::unique_ptr<PDFiumEngine> engine = InitializeEngine(
- &client, FILE_PATH_LITERAL("leading_trailing_spaces_per_text_run.pdf"));
- ASSERT_TRUE(engine);
- constexpr int kFirstRunStartIndex = 0;
- constexpr int kFirstRunEndIndex = 20;
- constexpr int kPageIndex = 0;
- absl::optional<AccessibilityTextRunInfo> text_run_info_1 =
- engine->GetTextRunInfo(kPageIndex, kFirstRunStartIndex);
- ASSERT_TRUE(text_run_info_1.has_value());
- const auto& actual_text_run_1 = text_run_info_1.value();
- EXPECT_EQ(21u, actual_text_run_1.len);
- EXPECT_TRUE(base::IsUnicodeWhitespace(
- engine->GetCharUnicode(kPageIndex, kFirstRunStartIndex)));
- gfx::RectF text_run_bounds = actual_text_run_1.bounds;
- EXPECT_TRUE(text_run_bounds.Contains(
- engine->GetCharBounds(kPageIndex, kFirstRunStartIndex)));
- // Last non-space character should fall in the bounding box of the text run.
- // Text run looks like this:
- // " Hello, world! \r\n "<17 characters><first Tj>
- // " \r\n "<4 characters><second Tj>
- // " "<1 character><third Tj starting spaces>
- // Finally generated text run: " Hello, world! \r\n \r\n "
- constexpr int kFirstRunLastNonSpaceCharIndex = 13;
- EXPECT_FALSE(base::IsUnicodeWhitespace(
- engine->GetCharUnicode(kPageIndex, kFirstRunLastNonSpaceCharIndex)));
- EXPECT_TRUE(text_run_bounds.Contains(
- engine->GetCharBounds(kPageIndex, kFirstRunLastNonSpaceCharIndex)));
- EXPECT_TRUE(base::IsUnicodeWhitespace(
- engine->GetCharUnicode(kPageIndex, kFirstRunEndIndex)));
- 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.
- constexpr int kSecondRunStartIndex = 21;
- constexpr int kSecondRunEndIndex = 36;
- // Test the properties of second text run.
- // Note: The leading spaces in second text run are accounted for in the end
- // of first text run. Hence we won't see a space leading the second text run.
- absl::optional<AccessibilityTextRunInfo> text_run_info_2 =
- engine->GetTextRunInfo(kPageIndex, kSecondRunStartIndex);
- ASSERT_TRUE(text_run_info_2.has_value());
- const auto& actual_text_run_2 = text_run_info_2.value();
- EXPECT_EQ(16u, actual_text_run_2.len);
- EXPECT_FALSE(base::IsUnicodeWhitespace(
- engine->GetCharUnicode(kPageIndex, kSecondRunStartIndex)));
- text_run_bounds = actual_text_run_2.bounds;
- EXPECT_TRUE(text_run_bounds.Contains(
- engine->GetCharBounds(kPageIndex, kSecondRunStartIndex)));
- // Last non-space character should fall in the bounding box of the text run.
- // Text run looks like this:
- // "Goodbye, world! "<19 characters><first Tj>
- // Finally generated text run: "Goodbye, world! "
- constexpr int kSecondRunLastNonSpaceCharIndex = 35;
- EXPECT_FALSE(base::IsUnicodeWhitespace(
- engine->GetCharUnicode(kPageIndex, kSecondRunLastNonSpaceCharIndex)));
- EXPECT_TRUE(text_run_bounds.Contains(
- engine->GetCharBounds(kPageIndex, kSecondRunLastNonSpaceCharIndex)));
- EXPECT_TRUE(base::IsUnicodeWhitespace(
- engine->GetCharUnicode(kPageIndex, kSecondRunEndIndex)));
- EXPECT_FALSE(text_run_bounds.Contains(
- engine->GetCharBounds(kPageIndex, kSecondRunEndIndex)));
- }
- TEST_F(PDFiumPageTextTest, GetTextRunInfo) {
- TestClient client;
- std::unique_ptr<PDFiumEngine> engine =
- InitializeEngine(&client, FILE_PATH_LITERAL("weblinks.pdf"));
- ASSERT_TRUE(engine);
- int current_char_index = 0;
- AccessibilityTextStyleInfo expected_style_1 = {
- "Times-Roman",
- 0,
- AccessibilityTextRenderMode::kFill,
- 12,
- 0xff000000,
- 0xff000000,
- false,
- false};
- AccessibilityTextStyleInfo expected_style_2 = {
- "Helvetica", 0, AccessibilityTextRenderMode::kFill,
- 16, 0xff000000, 0xff000000,
- false, false};
- // 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.
- AccessibilityTextRunInfo expected_text_runs[] = {
- {7, gfx::RectF(26.666666f, 189.333333f, 38.666672f, 13.333344f),
- AccessibilityTextDirection::kLeftToRight, expected_style_1},
- {16, gfx::RectF(70.666664f, 189.333333f, 108.0f, 14.666672f),
- AccessibilityTextDirection::kLeftToRight, expected_style_1},
- {20, gfx::RectF(181.333333f, 189.333333f, 117.333333f, 14.666672f),
- AccessibilityTextDirection::kLeftToRight, expected_style_1},
- {9, gfx::RectF(28.0f, 117.33334f, 89.333328f, 20.0f),
- AccessibilityTextDirection::kLeftToRight, expected_style_2},
- {15, gfx::RectF(126.66666f, 117.33334f, 137.33334f, 20.0f),
- AccessibilityTextDirection::kLeftToRight, expected_style_2},
- {20, gfx::RectF(266.66666f, 118.66666f, 169.33334f, 18.666664f),
- AccessibilityTextDirection::kLeftToRight, expected_style_2},
- {5, gfx::RectF(28.0f, 65.333336f, 40.0f, 18.666664f),
- AccessibilityTextDirection::kLeftToRight, expected_style_2},
- {17, gfx::RectF(77.333336f, 64.0f, 160.0f, 20.0f),
- AccessibilityTextDirection::kLeftToRight, expected_style_2}};
- if (UsingTestFonts()) {
- expected_text_runs[4].bounds =
- gfx::RectF(126.66666f, 117.33334f, 137.33334f, 21.33334f);
- expected_text_runs[5].bounds =
- gfx::RectF(266.66666f, 118.66666f, 170.66666f, 20.0f);
- expected_text_runs[7].bounds =
- gfx::RectF(77.333336f, 64.0f, 160.0f, 21.33333f);
- }
- // Test negative char index returns nullopt
- absl::optional<AccessibilityTextRunInfo> text_run_info_result =
- engine->GetTextRunInfo(0, -1);
- ASSERT_FALSE(text_run_info_result.has_value());
- // Test valid char index returns expected text run info and expected text
- // style info
- for (const auto& expected_text_run : expected_text_runs) {
- text_run_info_result = engine->GetTextRunInfo(0, current_char_index);
- ASSERT_TRUE(text_run_info_result.has_value());
- const auto& actual_text_run = text_run_info_result.value();
- CompareTextRuns(expected_text_run, actual_text_run);
- current_char_index += actual_text_run.len;
- }
- // Test char index outside char range returns nullopt
- PDFiumPage& page = GetPDFiumPageForTest(*engine, 0);
- EXPECT_EQ(page.GetCharCount(), current_char_index);
- text_run_info_result = engine->GetTextRunInfo(0, current_char_index);
- ASSERT_FALSE(text_run_info_result.has_value());
- }
- TEST_F(PDFiumPageTextTest, HighlightTextRunInfo) {
- TestClient client;
- std::unique_ptr<PDFiumEngine> engine =
- InitializeEngine(&client, FILE_PATH_LITERAL("highlights.pdf"));
- ASSERT_TRUE(engine);
- ASSERT_EQ(1, engine->GetNumberOfPages());
- // Highlights span across text run indices 0, 2 and 3.
- static const AccessibilityTextStyleInfo kExpectedStyle = {
- "Helvetica", 0, AccessibilityTextRenderMode::kFill,
- 16, 0xff000000, 0xff000000,
- false, false};
- AccessibilityTextRunInfo expected_text_runs[] = {
- {5, gfx::RectF(1.3333334f, 198.66667f, 46.666668f, 14.666672f),
- AccessibilityTextDirection::kLeftToRight, kExpectedStyle},
- {7, gfx::RectF(50.666668f, 198.66667f, 47.999996f, 17.333328f),
- AccessibilityTextDirection::kLeftToRight, kExpectedStyle},
- {7, gfx::RectF(106.66666f, 198.66667f, 73.333336f, 18.666672f),
- AccessibilityTextDirection::kLeftToRight, kExpectedStyle},
- {2, gfx::RectF(181.33333f, 202.66667f, 16.0f, 14.66667f),
- AccessibilityTextDirection::kNone, kExpectedStyle},
- {2, gfx::RectF(198.66667f, 202.66667f, 21.333328f, 10.666672f),
- AccessibilityTextDirection::kLeftToRight, kExpectedStyle}};
- if (UsingTestFonts()) {
- 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;
- for (const auto& expected_text_run : expected_text_runs) {
- absl::optional<AccessibilityTextRunInfo> text_run_info_result =
- engine->GetTextRunInfo(0, current_char_index);
- ASSERT_TRUE(text_run_info_result.has_value());
- const auto& actual_text_run = text_run_info_result.value();
- CompareTextRuns(expected_text_run, actual_text_run);
- current_char_index += actual_text_run.len;
- }
- }
- using PDFiumPageHighlightTest = PDFiumTestBase;
- TEST_F(PDFiumPageHighlightTest, PopulateHighlights) {
- struct ExpectedHighlight {
- int32_t start_char_index;
- int32_t char_count;
- gfx::Rect bounding_rect;
- uint32_t color;
- };
- 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 ExpectedHighlight kExpectedHighlights[] = {
- {0, 5, {5, 196, 49, 26}, kHighlightDefaultColor},
- {12, 7, {110, 196, 77, 26}, kHighlightRedColor},
- {20, 1, {192, 196, 13, 26}, kHighlightNoColor}};
- TestClient client;
- std::unique_ptr<PDFiumEngine> engine =
- InitializeEngine(&client, FILE_PATH_LITERAL("highlights.pdf"));
- ASSERT_TRUE(engine);
- ASSERT_EQ(1, engine->GetNumberOfPages());
- PDFiumPage& page = GetPDFiumPageForTest(*engine, 0);
- page.PopulateAnnotations();
- ASSERT_EQ(std::size(kExpectedHighlights), page.highlights_.size());
- for (size_t i = 0; i < page.highlights_.size(); ++i) {
- ASSERT_EQ(kExpectedHighlights[i].start_char_index,
- page.highlights_[i].start_char_index);
- ASSERT_EQ(kExpectedHighlights[i].char_count,
- page.highlights_[i].char_count);
- EXPECT_EQ(kExpectedHighlights[i].bounding_rect,
- page.highlights_[i].bounding_rect);
- ASSERT_EQ(kExpectedHighlights[i].color, page.highlights_[i].color);
- }
- }
- using PDFiumPageTextFieldTest = PDFiumTestBase;
- TEST_F(PDFiumPageTextFieldTest, PopulateTextFields) {
- struct ExpectedTextField {
- const char* name;
- const char* value;
- gfx::Rect bounding_rect;
- int flags;
- };
- static const ExpectedTextField kExpectedTextFields[] = {
- {"Text Box", "Text", {138, 230, 135, 41}, 0},
- {"ReadOnly", "Elephant", {138, 163, 135, 41}, 1},
- {"Required", "Required Field", {138, 303, 135, 34}, 2},
- {"Password", "", {138, 356, 135, 35}, 8192}};
- TestClient client;
- std::unique_ptr<PDFiumEngine> engine =
- InitializeEngine(&client, FILE_PATH_LITERAL("form_text_fields.pdf"));
- ASSERT_TRUE(engine);
- ASSERT_EQ(1, engine->GetNumberOfPages());
- PDFiumPage& page = GetPDFiumPageForTest(*engine, 0);
- page.PopulateAnnotations();
- size_t text_fields_count = page.text_fields_.size();
- ASSERT_EQ(std::size(kExpectedTextFields), text_fields_count);
- 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);
- EXPECT_EQ(kExpectedTextFields[i].bounding_rect,
- page.text_fields_[i].bounding_rect);
- EXPECT_EQ(kExpectedTextFields[i].flags, page.text_fields_[i].flags);
- }
- }
- using PDFiumPageChoiceFieldTest = PDFiumTestBase;
- TEST_F(PDFiumPageChoiceFieldTest, PopulateChoiceFields) {
- struct ExpectedChoiceFieldOption {
- const char* name;
- bool is_selected;
- };
- struct ExpectedChoiceField {
- const char* name;
- std::vector<struct ExpectedChoiceFieldOption> options;
- gfx::Rect bounding_rect;
- int flags;
- };
- static const ExpectedChoiceField kExpectedChoiceFields[] = {
- {"Listbox_SingleSelect",
- {{"Foo", false}, {"Bar", false}, {"Qux", false}},
- {138, 296, 135, 41},
- 0},
- {"Combo1",
- {{"Apple", false}, {"Banana", true}, {"Cherry", false}},
- {138, 230, 135, 41},
- 131072},
- {"Listbox_ReadOnly",
- {{"Dog", false}, {"Elephant", false}, {"Frog", false}},
- {138, 96, 135, 41},
- 1},
- {"Listbox_MultiSelectMultipleIndices",
- {
- {"Albania", false},
- {"Belgium", true},
- {"Croatia", false},
- {"Denmark", true},
- {"Estonia", false},
- },
- {138, 430, 135, 41},
- 2097152},
- {"Listbox_MultiSelectMultipleValues",
- {
- {"Alpha", false},
- {"Beta", false},
- {"Gamma", true},
- {"Delta", false},
- {"Epsilon", true},
- },
- {138, 496, 135, 41},
- 2097152},
- {"Listbox_MultiSelectMultipleMismatch",
- {
- {"Alligator", true},
- {"Bear", false},
- {"Cougar", true},
- {"Deer", false},
- {"Echidna", false},
- },
- {138, 563, 135, 41},
- 2097152}};
- TestClient client;
- std::unique_ptr<PDFiumEngine> engine =
- InitializeEngine(&client, FILE_PATH_LITERAL("form_choice_fields.pdf"));
- ASSERT_TRUE(engine);
- ASSERT_EQ(1, engine->GetNumberOfPages());
- PDFiumPage& page = GetPDFiumPageForTest(*engine, 0);
- page.PopulateAnnotations();
- size_t choice_fields_count = page.choice_fields_.size();
- ASSERT_EQ(std::size(kExpectedChoiceFields), choice_fields_count);
- for (size_t i = 0; i < choice_fields_count; ++i) {
- EXPECT_EQ(kExpectedChoiceFields[i].name, page.choice_fields_[i].name);
- size_t choice_field_options_count = page.choice_fields_[i].options.size();
- ASSERT_EQ(std::size(kExpectedChoiceFields[i].options),
- choice_field_options_count);
- for (size_t j = 0; j < choice_field_options_count; ++j) {
- EXPECT_EQ(kExpectedChoiceFields[i].options[j].name,
- page.choice_fields_[i].options[j].name);
- EXPECT_EQ(kExpectedChoiceFields[i].options[j].is_selected,
- page.choice_fields_[i].options[j].is_selected);
- }
- EXPECT_EQ(kExpectedChoiceFields[i].bounding_rect,
- page.choice_fields_[i].bounding_rect);
- EXPECT_EQ(kExpectedChoiceFields[i].flags, page.choice_fields_[i].flags);
- }
- }
- using PDFiumPageButtonTest = PDFiumTestBase;
- TEST_F(PDFiumPageButtonTest, PopulateButtons) {
- struct ExpectedButton {
- const char* name;
- const char* value;
- int type;
- int flags;
- bool is_checked;
- uint32_t control_count;
- int control_index;
- gfx::Rect bounding_rect;
- };
- static const ExpectedButton kExpectedButtons[] = {{"readOnlyCheckbox",
- "Yes",
- FPDF_FORMFIELD_CHECKBOX,
- 1,
- true,
- 1,
- 0,
- {185, 43, 28, 28}},
- {"checkbox",
- "Yes",
- FPDF_FORMFIELD_CHECKBOX,
- 2,
- false,
- 1,
- 0,
- {185, 96, 28, 28}},
- {"RadioButton",
- "value1",
- FPDF_FORMFIELD_RADIOBUTTON,
- 49154,
- false,
- 2,
- 0,
- {185, 243, 28, 28}},
- {"RadioButton",
- "value2",
- FPDF_FORMFIELD_RADIOBUTTON,
- 49154,
- true,
- 2,
- 1,
- {252, 243, 27, 28}},
- {"PushButton",
- "",
- FPDF_FORMFIELD_PUSHBUTTON,
- 65536,
- false,
- 0,
- -1,
- {118, 270, 55, 67}}};
- TestClient client;
- std::unique_ptr<PDFiumEngine> engine =
- InitializeEngine(&client, FILE_PATH_LITERAL("form_buttons.pdf"));
- ASSERT_TRUE(engine);
- ASSERT_EQ(1, engine->GetNumberOfPages());
- PDFiumPage& page = GetPDFiumPageForTest(*engine, 0);
- page.PopulateAnnotations();
- size_t buttons_count = page.buttons_.size();
- ASSERT_EQ(std::size(kExpectedButtons), buttons_count);
- for (size_t i = 0; i < buttons_count; ++i) {
- EXPECT_EQ(kExpectedButtons[i].name, page.buttons_[i].name);
- EXPECT_EQ(kExpectedButtons[i].value, page.buttons_[i].value);
- EXPECT_EQ(kExpectedButtons[i].type, page.buttons_[i].type);
- EXPECT_EQ(kExpectedButtons[i].flags, page.buttons_[i].flags);
- EXPECT_EQ(kExpectedButtons[i].is_checked, page.buttons_[i].is_checked);
- EXPECT_EQ(kExpectedButtons[i].control_count,
- page.buttons_[i].control_count);
- EXPECT_EQ(kExpectedButtons[i].control_index,
- page.buttons_[i].control_index);
- EXPECT_EQ(kExpectedButtons[i].bounding_rect,
- page.buttons_[i].bounding_rect);
- }
- }
- 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, thumbnail.image_size());
- EXPECT_EQ(device_pixel_ratio, thumbnail.device_pixel_ratio());
- auto image_info =
- SkImageInfo::Make(gfx::SizeToSkISize(thumbnail.image_size()),
- kRGBA_8888_SkColorType, kPremul_SkAlphaType);
- int stride = thumbnail.stride();
- ASSERT_GT(stride, 0);
- ASSERT_EQ(image_info.minRowBytes(), static_cast<size_t>(stride));
- std::vector<uint8_t> data = thumbnail.TakeData();
- sk_sp<SkImage> image = SkImage::MakeRasterCopy(
- SkPixmap(image_info, data.data(), image_info.minRowBytes()));
- ASSERT_TRUE(image);
- base::FilePath expectation_png_file_path = GetThumbnailTestData(
- expectation_file_prefix, page_index, device_pixel_ratio);
- EXPECT_TRUE(MatchesPngFile(image.get(), expectation_png_file_path));
- }
- };
- 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");
- }
- }
- // For crbug.com/1248455
- TEST_F(PDFiumPageThumbnailTest, GenerateThumbnailForAnnotation) {
- TestClient client;
- std::unique_ptr<PDFiumEngine> engine =
- InitializeEngine(&client, FILE_PATH_LITERAL("signature_widget.pdf"));
- TestGenerateThumbnail(*engine, /*page_index=*/0, /*device_pixel_ratio=*/1,
- /*expected_thumbnail_size=*/{140, 140},
- "signature_widget");
- TestGenerateThumbnail(*engine, /*page_index=*/0, /*device_pixel_ratio=*/2,
- /*expected_thumbnail_size=*/{255, 255},
- "signature_widget");
- }
- } // namespace chrome_pdf
|