Commit 5bee2104 authored by Virender Singh's avatar Virender Singh Committed by Commit Bot

Adding underlying text range to PDF links

This CL updates the Link structure to include the underlying text range.
The underlying text range is being populated using the newly added
FPDFLink_GetTextRange() API. This would enable us to position links along
with text in the accessibility tree.

Bug: 981448
Change-Id: I4551f70c21e2846f9a85c19c982f17dc52e0b25c
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1710275
Commit-Queue: Virender Singh <virens@microsoft.com>
Reviewed-by: default avatarLei Zhang <thestig@chromium.org>
Reviewed-by: default avatarKevin Babbitt <kbabbitt@microsoft.com>
Cr-Commit-Position: refs/heads/master@{#686341}
parent 6228a865
...@@ -151,11 +151,14 @@ if (enable_pdf) { ...@@ -151,11 +151,14 @@ if (enable_pdf) {
"test/test_client.h", "test/test_client.h",
"test/test_document_loader.cc", "test/test_document_loader.cc",
"test/test_document_loader.h", "test/test_document_loader.h",
"test/test_utils.cc",
"test/test_utils.h",
] ]
deps = [ deps = [
":pdf", ":pdf",
"//base", "//base",
"//testing/gtest",
] ]
} }
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#include "pdf/draw_utils/coordinates.h" #include "pdf/draw_utils/coordinates.h"
#include "pdf/test/test_utils.h"
#include "ppapi/cpp/point.h" #include "ppapi/cpp/point.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
...@@ -26,18 +27,6 @@ void CompareInsetSizes(const PageInsetSizes& expected_insets, ...@@ -26,18 +27,6 @@ void CompareInsetSizes(const PageInsetSizes& expected_insets,
EXPECT_EQ(expected_insets.bottom, given_insets.bottom); EXPECT_EQ(expected_insets.bottom, given_insets.bottom);
} }
void CompareRect(const pp::Rect& expected_rect, const pp::Rect& given_rect) {
EXPECT_EQ(expected_rect.x(), given_rect.x());
EXPECT_EQ(expected_rect.y(), given_rect.y());
EXPECT_EQ(expected_rect.width(), given_rect.width());
EXPECT_EQ(expected_rect.height(), given_rect.height());
}
void CompareSize(const pp::Size& expected_size, const pp::Size& given_size) {
EXPECT_EQ(expected_size.width(), given_size.width());
EXPECT_EQ(expected_size.height(), given_size.height());
}
} // namespace } // namespace
TEST(CoordinateTest, AdjustBottomGapForRightSidePage) { TEST(CoordinateTest, AdjustBottomGapForRightSidePage) {
......
...@@ -430,7 +430,7 @@ int PDFiumPage::GetLink(int char_index, LinkTarget* target) { ...@@ -430,7 +430,7 @@ int PDFiumPage::GetLink(int char_index, LinkTarget* target) {
PageOrientation::kOriginal) PageOrientation::kOriginal)
.point()); .point());
for (size_t i = 0; i < links_.size(); ++i) { for (size_t i = 0; i < links_.size(); ++i) {
for (const auto& rect : links_[i].rects) { for (const auto& rect : links_[i].bounding_rects) {
if (rect.Contains(origin)) { if (rect.Contains(origin)) {
if (target) if (target)
target->url = links_[i].url; target->url = links_[i].url;
...@@ -495,8 +495,11 @@ void PDFiumPage::CalculateLinks() { ...@@ -495,8 +495,11 @@ void PDFiumPage::CalculateLinks() {
PageOrientation::kOriginal); PageOrientation::kOriginal);
if (rect.IsEmpty()) if (rect.IsEmpty())
continue; continue;
link.rects.push_back(rect); link.bounding_rects.push_back(rect);
} }
FPDF_BOOL is_link_over_text = FPDFLink_GetTextRange(
links, i, &link.start_char_index, &link.char_count);
DCHECK(is_link_over_text);
links_.push_back(link); links_.push_back(link);
} }
FPDFLink_CloseWebLinks(links); FPDFLink_CloseWebLinks(links);
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include "base/gtest_prod_util.h"
#include "base/optional.h" #include "base/optional.h"
#include "base/strings/string16.h" #include "base/strings/string16.h"
#include "pdf/page_orientation.h" #include "pdf/page_orientation.h"
...@@ -134,6 +135,9 @@ class PDFiumPage { ...@@ -134,6 +135,9 @@ class PDFiumPage {
FPDF_TEXTPAGE text_page() const { return text_page_.get(); } FPDF_TEXTPAGE text_page() const { return text_page_.get(); }
private: private:
friend class PDFiumPageLinkTest;
FRIEND_TEST_ALL_PREFIXES(PDFiumPageLinkTest, TestLinkGeneration);
// Returns a link index if the given character index is over a link, or -1 // Returns a link index if the given character index is over a link, or -1
// otherwise. // otherwise.
int GetLink(int char_index, LinkTarget* target); int GetLink(int char_index, LinkTarget* target);
...@@ -163,9 +167,15 @@ class PDFiumPage { ...@@ -163,9 +167,15 @@ class PDFiumPage {
Link(const Link& that); Link(const Link& that);
~Link(); ~Link();
// Represents start index of underlying text range. Should be -1 if the link
// is not over text.
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;
// Valid for links with external urls only.
std::string url; std::string url;
// Bounding rectangles of characters.
std::vector<pp::Rect> rects;
}; };
PDFiumEngine* engine_; PDFiumEngine* engine_;
......
...@@ -6,11 +6,25 @@ ...@@ -6,11 +6,25 @@
#include "base/logging.h" #include "base/logging.h"
#include "base/test/gtest_util.h" #include "base/test/gtest_util.h"
#include "pdf/pdfium/pdfium_engine.h"
#include "pdf/pdfium/pdfium_test_base.h"
#include "pdf/test/test_client.h"
#include "pdf/test/test_utils.h"
#include "ppapi/c/private/ppb_pdf.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
#if defined(OS_CHROMEOS)
#include "base/system/sys_info.h"
#endif
namespace chrome_pdf { namespace chrome_pdf {
namespace { namespace {
bool IsValidLinkForTesting(const std::string& url) {
return !url.empty();
}
TEST(PDFiumPageTest, ToPDFiumRotation) { TEST(PDFiumPageTest, ToPDFiumRotation) {
EXPECT_EQ(ToPDFiumRotation(PageOrientation::kOriginal), 0); EXPECT_EQ(ToPDFiumRotation(PageOrientation::kOriginal), 0);
EXPECT_EQ(ToPDFiumRotation(PageOrientation::kClockwise90), 1); EXPECT_EQ(ToPDFiumRotation(PageOrientation::kClockwise90), 1);
...@@ -28,4 +42,64 @@ TEST(PDFiumPageDeathTest, ToPDFiumRotation) { ...@@ -28,4 +42,64 @@ TEST(PDFiumPageDeathTest, ToPDFiumRotation) {
} }
} // namespace } // namespace
} // namespace chrome_pdf
class PDFiumPageLinkTest : public PDFiumTestBase {
public:
PDFiumPageLinkTest() {
PDFiumPage::SetIsValidLinkFunctionForTesting(&IsValidLinkForTesting);
}
~PDFiumPageLinkTest() override {
PDFiumPage::SetIsValidLinkFunctionForTesting(nullptr);
}
const std::vector<PDFiumPage::Link>& GetLinks(PDFiumEngine* engine,
int page_index) {
PDFiumPage* page = GetPDFiumPageForTest(engine, page_index);
DCHECK(page);
page->CalculateLinks();
return page->links_;
}
DISALLOW_COPY_AND_ASSIGN(PDFiumPageLinkTest);
};
TEST_F(PDFiumPageLinkTest, TestLinkGeneration) {
TestClient client;
std::unique_ptr<PDFiumEngine> engine =
InitializeEngine(&client, FILE_PATH_LITERAL("weblinks.pdf"));
ASSERT_TRUE(engine);
ASSERT_EQ(1, engine->GetNumberOfPages());
bool is_chromeos = false;
#if defined(OS_CHROMEOS)
is_chromeos = base::SysInfo::IsRunningOnChromeOS();
#endif
const std::vector<PDFiumPage::Link>& links = GetLinks(engine.get(), 0);
ASSERT_EQ(2u, links.size());
const PDFiumPage::Link& link = links[0];
EXPECT_EQ("http://yahoo.com", link.url);
EXPECT_EQ(7, link.start_char_index);
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]);
} else {
CompareRect({75, 191, 110, 16}, link.bounding_rects[0]);
}
const PDFiumPage::Link& second_link = links[1];
EXPECT_EQ("http://bing.com", second_link.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 (is_chromeos) {
CompareRect({131, 120, 138, 22}, second_link.bounding_rects[0]);
} else {
CompareRect({131, 121, 138, 20}, second_link.bounding_rects[0]);
}
}
} // namespace chrome_pdf
\ No newline at end of file
{{header}}
{{object 1 0}} <<
/Type /Catalog
/Pages 2 0 R
>>
endobj
{{object 2 0}} <<
/Type /Pages
/MediaBox [0 0 400 200]
/Count 1
/Kids [3 0 R]
>>
endobj
{{object 3 0}} <<
/Type /Page
/Parent 2 0 R
/Resources <<
/Font <<
/F1 4 0 R
/F2 5 0 R
>>
>>
/Contents 6 0 R
>>
endobj
{{object 4 0}} <<
/Type /Font
/Subtype /Type1
/BaseFont /Times-Roman
>>
endobj
{{object 5 0}} <<
/Type /Font
/Subtype /Type1
/BaseFont /Helvetica
>>
endobj
{{object 6 0}} <<
{{streamlen}}
>>
stream
BT
20 50 Td
/F1 12 Tf
(Hello, http://yahoo.com! nice meeting you) Tj
0 50 Td
/F2 16 Tf
(Goodbye, http://bing.com! nice meeting you) Tj
ET
endstream
endobj
{{xref}}
{{trailer}}
{{startxref}}
%%EOF
This diff was suppressed by a .gitattributes entry.
// 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/test/test_utils.h"
#include "ppapi/cpp/rect.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace chrome_pdf {
void CompareRect(const pp::Rect& expected_rect, const pp::Rect& given_rect) {
EXPECT_EQ(expected_rect.x(), given_rect.x());
EXPECT_EQ(expected_rect.y(), given_rect.y());
EXPECT_EQ(expected_rect.width(), given_rect.width());
EXPECT_EQ(expected_rect.height(), given_rect.height());
}
void CompareSize(const pp::Size& expected_size, const pp::Size& given_size) {
EXPECT_EQ(expected_size.width(), given_size.width());
EXPECT_EQ(expected_size.height(), given_size.height());
}
} // namespace chrome_pdf
\ No newline at end of file
// 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.
#ifndef PDF_TEST_TEST_UTILS_H_
#define PDF_TEST_TEST_UTILS_H_
namespace pp {
class Rect;
class Size;
} // namespace pp
namespace chrome_pdf {
void CompareRect(const pp::Rect& expected_rect, const pp::Rect& given_rect);
void CompareSize(const pp::Size& expected_size, const pp::Size& given_size);
} // namespace chrome_pdf
#endif // PDF_TEST_TEST_UTILS_H_
\ No newline at end of file
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment