Commit 8cf9925f authored by Ankit Kumar 🌪️'s avatar Ankit Kumar 🌪️ Committed by Commit Bot

PDF Accessibility: Adding links and images in PDFAccessibilityTree

Links and images are sent in a vector from the plugin layer. This CL
uses the vectors sent to create link and image nodes, and adds them in
the PDFAccessibilityTree.

Tests have been added to validate PdfAccessibilityTree creation mocking
the data being sent from the plugin process.

End to end tests will be added in another CL as vectors of links and
images are not being populated as of right now. Once they are added in
the plugin layer then we can add tests for the same.

Bug: 981448
Change-Id: I5eecf643c0c50e0ec594e340344776f1f0d7a587
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1704718
Commit-Queue: Ankit Kumar 🌪️ <ankk@microsoft.com>
Reviewed-by: default avatarLei Zhang <thestig@chromium.org>
Reviewed-by: default avatarKevin Babbitt <kbabbitt@microsoft.com>
Cr-Commit-Position: refs/heads/master@{#691482}
parent 4f1670c5
...@@ -94,7 +94,15 @@ class PdfAccessibilityTree : public content::PluginAXTreeSource { ...@@ -94,7 +94,15 @@ class PdfAccessibilityTree : public content::PluginAXTreeSource {
const gfx::RectF& page_bounds, const gfx::RectF& page_bounds,
uint32_t page_index, uint32_t page_index,
const std::vector<PP_PrivateAccessibilityTextRunInfo>& text_runs, const std::vector<PP_PrivateAccessibilityTextRunInfo>& text_runs,
const std::vector<PP_PrivateAccessibilityCharInfo>& chars); const std::vector<PP_PrivateAccessibilityCharInfo>& chars,
const std::vector<ppapi::PdfAccessibilityLinkInfo>& links,
const std::vector<ppapi::PdfAccessibilityImageInfo>& images);
void AddRemainingAnnotations(
ui::AXNodeData* page_node,
const gfx::RectF& page_bounds,
base::span<const ppapi::PdfAccessibilityLinkInfo> links,
base::span<const ppapi::PdfAccessibilityImageInfo> images,
ui::AXNodeData* para_node);
void ComputeParagraphAndHeadingThresholds( void ComputeParagraphAndHeadingThresholds(
const std::vector<PP_PrivateAccessibilityTextRunInfo>& text_runs, const std::vector<PP_PrivateAccessibilityTextRunInfo>& text_runs,
...@@ -119,6 +127,18 @@ class PdfAccessibilityTree : public content::PluginAXTreeSource { ...@@ -119,6 +127,18 @@ class PdfAccessibilityTree : public content::PluginAXTreeSource {
const std::vector<PP_PrivateAccessibilityCharInfo>& chars, const std::vector<PP_PrivateAccessibilityCharInfo>& chars,
uint32_t char_index, uint32_t char_index,
const gfx::RectF& page_bounds); const gfx::RectF& page_bounds);
ui::AXNodeData* CreateLinkNode(const ppapi::PdfAccessibilityLinkInfo& link,
const gfx::RectF& page_bounds);
ui::AXNodeData* CreateImageNode(const ppapi::PdfAccessibilityImageInfo& image,
const gfx::RectF& page_bounds);
void AddTextToLinkNode(
uint32_t start_text_run_index,
uint32_t end_text_run_index,
const std::vector<PP_PrivateAccessibilityTextRunInfo>& text_runs,
const std::vector<PP_PrivateAccessibilityCharInfo>& chars,
const gfx::RectF& page_bounds,
uint32_t* char_index,
ui::AXNodeData* link_node);
float GetDeviceScaleFactor() const; float GetDeviceScaleFactor() const;
content::RenderAccessibility* GetRenderAccessibility(); content::RenderAccessibility* GetRenderAccessibility();
gfx::Transform* MakeTransformFromViewInfo(); gfx::Transform* MakeTransformFromViewInfo();
......
...@@ -27,10 +27,18 @@ const PP_PrivateAccessibilityTextRunInfo kSecondTextRun = { ...@@ -27,10 +27,18 @@ const PP_PrivateAccessibilityTextRunInfo kSecondTextRun = {
const PP_PrivateAccessibilityCharInfo kDummyCharsData[] = { const PP_PrivateAccessibilityCharInfo kDummyCharsData[] = {
{'H', 12}, {'e', 6}, {'l', 5}, {'l', 4}, {'o', 8}, {',', 4}, {'H', 12}, {'e', 6}, {'l', 5}, {'l', 4}, {'o', 8}, {',', 4},
{' ', 4}, {'w', 12}, {'o', 6}, {'r', 6}, {'l', 4}, {'d', 9}, {' ', 4}, {'w', 12}, {'o', 6}, {'r', 6}, {'l', 4}, {'d', 9},
{'!', 4}, {'\r', 0}, {'\n', 0}, {'G', 16}, {'o', 12}, {'o', 12}, {'!', 4}, {' ', 0}, {' ', 0}, {'G', 16}, {'o', 12}, {'o', 12},
{'d', 12}, {'b', 10}, {'y', 12}, {'e', 12}, {',', 4}, {' ', 6}, {'d', 12}, {'b', 10}, {'y', 12}, {'e', 12}, {',', 4}, {' ', 6},
{'w', 16}, {'o', 12}, {'r', 8}, {'l', 4}, {'d', 12}, {'!', 2}, {'w', 16}, {'o', 12}, {'r', 8}, {'l', 4}, {'d', 12}, {'!', 2},
}; };
const PP_PrivateAccessibilityTextRunInfo kFirstRunMultiLine = {
7, 12, PP_MakeFloatRectFromXYWH(26.0f, 189.0f, 84.0f, 13.0f)};
const PP_PrivateAccessibilityTextRunInfo kSecondRunMultiLine = {
8, 12, PP_MakeFloatRectFromXYWH(26.0f, 189.0f, 84.0f, 13.0f)};
const PP_PrivateAccessibilityTextRunInfo kThirdRunMultiLine = {
9, 12, PP_MakeFloatRectFromXYWH(26.0f, 189.0f, 84.0f, 13.0f)};
const PP_PrivateAccessibilityTextRunInfo kFourthRunMultiLine = {
6, 12, PP_MakeFloatRectFromXYWH(26.0f, 189.0f, 84.0f, 13.0f)};
void CompareRect(PP_Rect expected_rect, PP_Rect actual_rect) { void CompareRect(PP_Rect expected_rect, PP_Rect actual_rect) {
EXPECT_EQ(expected_rect.point.x, actual_rect.point.x); EXPECT_EQ(expected_rect.point.x, actual_rect.point.x);
...@@ -207,6 +215,207 @@ TEST_F(PdfAccessibilityTreeTest, TestAccessibilityDisabledDuringPDFLoad) { ...@@ -207,6 +215,207 @@ TEST_F(PdfAccessibilityTreeTest, TestAccessibilityDisabledDuringPDFLoad) {
chars_, links_, images_); chars_, links_, images_);
} }
TEST_F(PdfAccessibilityTreeTest, TestPdfAccessibilityTreeCreation) {
text_runs_.emplace_back(kFirstTextRun);
text_runs_.emplace_back(kSecondTextRun);
chars_.insert(chars_.end(), std::begin(kDummyCharsData),
std::end(kDummyCharsData));
ppapi::PdfAccessibilityLinkInfo link;
link.url = "www.cs.chromium.org";
link.text_run_index = 0;
link.text_run_count = 1;
links_.push_back(link);
ppapi::PdfAccessibilityImageInfo image;
image.alt_text = "Alternate text for image";
image.text_run_index = 2;
images_.push_back(image);
page_info_.text_run_count = text_runs_.size();
page_info_.char_count = chars_.size();
page_info_.link_count = links_.size();
page_info_.image_count = images_.size();
content::RenderFrame* render_frame = view_->GetMainRenderFrame();
render_frame->SetAccessibilityModeForTest(ui::AXMode::kWebContents);
ASSERT_TRUE(render_frame->GetRenderAccessibility());
FakeRendererPpapiHost host(view_->GetMainRenderFrame());
PP_Instance instance = 0;
pdf::PdfAccessibilityTree pdf_accessibility_tree(&host, instance);
pdf_accessibility_tree.SetAccessibilityViewportInfo(viewport_info_);
pdf_accessibility_tree.SetAccessibilityDocInfo(doc_info_);
pdf_accessibility_tree.SetAccessibilityPageInfo(page_info_, text_runs_,
chars_, links_, images_);
/*
* Expected tree structure
* Document
* ++ Region
* ++++ Paragraph
* ++++++ Link
* ++++ Paragraph
* ++++++ Static Text
* ++++++ Image
*/
ui::AXNode* root_node = pdf_accessibility_tree.GetRoot();
ASSERT_TRUE(root_node);
EXPECT_EQ(ax::mojom::Role::kDocument, root_node->data().role);
ASSERT_EQ(1u, root_node->children().size());
ui::AXNode* page_node = root_node->children()[0];
ASSERT_TRUE(page_node);
EXPECT_EQ(ax::mojom::Role::kRegion, page_node->data().role);
ASSERT_EQ(2u, page_node->children().size());
ui::AXNode* paragraph_node = page_node->children()[0];
ASSERT_TRUE(paragraph_node);
EXPECT_EQ(ax::mojom::Role::kParagraph, paragraph_node->data().role);
ASSERT_EQ(1u, paragraph_node->children().size());
ui::AXNode* link_node = paragraph_node->children()[0];
ASSERT_TRUE(link_node);
EXPECT_EQ(link.url,
link_node->GetStringAttribute(ax::mojom::StringAttribute::kUrl));
EXPECT_EQ(ax::mojom::Role::kLink, link_node->data().role);
ASSERT_EQ(1u, link_node->children().size());
paragraph_node = page_node->children()[1];
ASSERT_TRUE(paragraph_node);
EXPECT_EQ(ax::mojom::Role::kParagraph, paragraph_node->data().role);
ASSERT_EQ(2u, paragraph_node->children().size());
ui::AXNode* static_text_node = paragraph_node->children()[0];
ASSERT_TRUE(static_text_node);
EXPECT_EQ(ax::mojom::Role::kStaticText, static_text_node->data().role);
ASSERT_EQ(1u, static_text_node->children().size());
ui::AXNode* image_node = paragraph_node->children()[1];
ASSERT_TRUE(image_node);
EXPECT_EQ(ax::mojom::Role::kImage, image_node->data().role);
EXPECT_EQ(image.alt_text,
image_node->GetStringAttribute(ax::mojom::StringAttribute::kName));
}
TEST_F(PdfAccessibilityTreeTest, TestPreviousNextOnLine) {
text_runs_.emplace_back(kFirstRunMultiLine);
text_runs_.emplace_back(kSecondRunMultiLine);
text_runs_.emplace_back(kThirdRunMultiLine);
text_runs_.emplace_back(kFourthRunMultiLine);
chars_.insert(chars_.end(), std::begin(kDummyCharsData),
std::end(kDummyCharsData));
ppapi::PdfAccessibilityLinkInfo link;
link.url = "www.cs.chromium.org";
link.text_run_index = 2;
link.text_run_count = 2;
links_.push_back(link);
page_info_.text_run_count = text_runs_.size();
page_info_.char_count = chars_.size();
page_info_.link_count = links_.size();
content::RenderFrame* render_frame = view_->GetMainRenderFrame();
render_frame->SetAccessibilityModeForTest(ui::AXMode::kWebContents);
ASSERT_TRUE(render_frame->GetRenderAccessibility());
FakeRendererPpapiHost host(view_->GetMainRenderFrame());
PP_Instance instance = 0;
pdf::PdfAccessibilityTree pdf_accessibility_tree(&host, instance);
pdf_accessibility_tree.SetAccessibilityViewportInfo(viewport_info_);
pdf_accessibility_tree.SetAccessibilityDocInfo(doc_info_);
pdf_accessibility_tree.SetAccessibilityPageInfo(page_info_, text_runs_,
chars_, links_, images_);
/*
* Expected tree structure
* Document
* ++ Region
* ++++ Paragraph
* ++++++ Static Text
* ++++++++ Inline Text Box
* ++++++++ Inline Text Box
* ++++++ Link
* ++++++++ Static Text
* ++++++++++ Inline Text Box
* ++++++++++ Inline Text Box
*/
ui::AXNode* root_node = pdf_accessibility_tree.GetRoot();
ASSERT_TRUE(root_node);
EXPECT_EQ(ax::mojom::Role::kDocument, root_node->data().role);
ASSERT_EQ(1u, root_node->children().size());
ui::AXNode* page_node = root_node->children()[0];
ASSERT_TRUE(page_node);
EXPECT_EQ(ax::mojom::Role::kRegion, page_node->data().role);
ASSERT_EQ(1u, page_node->children().size());
ui::AXNode* paragraph_node = page_node->children()[0];
ASSERT_TRUE(paragraph_node);
EXPECT_EQ(ax::mojom::Role::kParagraph, paragraph_node->data().role);
ASSERT_EQ(2u, paragraph_node->children().size());
ui::AXNode* static_text_node = paragraph_node->children()[0];
ASSERT_TRUE(static_text_node);
EXPECT_EQ(ax::mojom::Role::kStaticText, static_text_node->data().role);
ASSERT_EQ(2u, static_text_node->children().size());
ui::AXNode* previous_inline_node = static_text_node->children()[0];
ASSERT_TRUE(previous_inline_node);
EXPECT_EQ(ax::mojom::Role::kInlineTextBox, previous_inline_node->data().role);
ui::AXNode* next_inline_node = static_text_node->children()[1];
ASSERT_TRUE(next_inline_node);
EXPECT_EQ(ax::mojom::Role::kInlineTextBox, next_inline_node->data().role);
ASSERT_EQ(next_inline_node->data().id,
previous_inline_node->GetIntAttribute(
ax::mojom::IntAttribute::kNextOnLineId));
ASSERT_EQ(previous_inline_node->data().id,
next_inline_node->GetIntAttribute(
ax::mojom::IntAttribute::kPreviousOnLineId));
ASSERT_FALSE(next_inline_node->HasIntAttribute(
ax::mojom::IntAttribute::kNextOnLineId));
ASSERT_FALSE(previous_inline_node->HasIntAttribute(
ax::mojom::IntAttribute::kPreviousOnLineId));
ui::AXNode* link_node = paragraph_node->children()[1];
ASSERT_TRUE(link_node);
EXPECT_EQ(link.url,
link_node->GetStringAttribute(ax::mojom::StringAttribute::kUrl));
EXPECT_EQ(ax::mojom::Role::kLink, link_node->data().role);
ASSERT_EQ(1u, link_node->children().size());
static_text_node = link_node->children()[0];
ASSERT_TRUE(static_text_node);
EXPECT_EQ(ax::mojom::Role::kStaticText, static_text_node->data().role);
ASSERT_EQ(2u, static_text_node->children().size());
previous_inline_node = static_text_node->children()[0];
ASSERT_TRUE(previous_inline_node);
EXPECT_EQ(ax::mojom::Role::kInlineTextBox, previous_inline_node->data().role);
next_inline_node = static_text_node->children()[1];
ASSERT_TRUE(next_inline_node);
EXPECT_EQ(ax::mojom::Role::kInlineTextBox, next_inline_node->data().role);
ASSERT_EQ(next_inline_node->data().id,
previous_inline_node->GetIntAttribute(
ax::mojom::IntAttribute::kNextOnLineId));
ASSERT_EQ(previous_inline_node->data().id,
next_inline_node->GetIntAttribute(
ax::mojom::IntAttribute::kPreviousOnLineId));
ASSERT_FALSE(next_inline_node->HasIntAttribute(
ax::mojom::IntAttribute::kNextOnLineId));
ASSERT_FALSE(previous_inline_node->HasIntAttribute(
ax::mojom::IntAttribute::kPreviousOnLineId));
}
TEST_F(PdfAccessibilityTreeTest, TextRunsAndCharsMismatch) { TEST_F(PdfAccessibilityTreeTest, TextRunsAndCharsMismatch) {
// |chars_| and |text_runs_| span over the same page text. They should denote // |chars_| and |text_runs_| span over the same page text. They should denote
// the same page text size, but |text_runs_| is incorrect and only denotes 1 // the same page text size, but |text_runs_| is incorrect and only denotes 1
......
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