Commit 319f3b00 authored by Martin Robinson's avatar Martin Robinson Committed by Commit Bot

Expose AtkText on more elements

This change exposes the AtkText interface on all accessibility elements
and uses the, now shared, ComputeHypertext in order to compute composite
text for elements that have multiple children. Once we start exposing
the hypertext interface, we can start testing the embedding of objects
into the hypertext itself. The plan is also to eventually expose the
interface on objects that need it.

Unfortunately, since hypertext computation is now triggered by the
content code, we must move the existing AtkText unit test to content as
well alongside the new one.

Bug: 866337
Change-Id: I8cc738dd0e14cf95ecdffa2370d242fb447aa9b6
Reviewed-on: https://chromium-review.googlesource.com/1190782
Commit-Queue: Martin Robinson <mrobinson@igalia.com>
Reviewed-by: default avatarDominic Mazzoni <dmazzoni@chromium.org>
Cr-Commit-Position: refs/heads/master@{#586772}
parent 43644c94
......@@ -46,6 +46,10 @@ void BrowserAccessibilityAuraLinux::OnDataChanged() {
node_->DataChanged();
}
void BrowserAccessibilityAuraLinux::UpdatePlatformAttributes() {
GetNode()->UpdateHypertext();
}
bool BrowserAccessibilityAuraLinux::IsNative() const {
return true;
}
......
......@@ -22,7 +22,11 @@ class BrowserAccessibilityAuraLinux : public BrowserAccessibility {
~BrowserAccessibilityAuraLinux() override;
ui::AXPlatformNodeAuraLinux* GetNode() const;
CONTENT_EXPORT ui::AXPlatformNodeAuraLinux* GetNode() const;
// This is used to call UpdateHypertext, when a node needs to be
// updated for some other reason other than via OnAtomicUpdateFinished.
void UpdatePlatformAttributes() override;
// BrowserAccessibility methods.
void OnDataChanged() override;
......
// Copyright (c) 2018 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 "content/browser/accessibility/browser_accessibility_auralinux.h"
#include <atk/atk.h>
#include <memory>
#include <string>
#include <vector>
#include "content/browser/accessibility/browser_accessibility_manager.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/accessibility/platform/ax_platform_node_auralinux.h"
namespace content {
class BrowserAccessibilityAuraLinuxTest : public testing::Test {
public:
BrowserAccessibilityAuraLinuxTest();
~BrowserAccessibilityAuraLinuxTest() override;
private:
void SetUp() override;
content::TestBrowserThreadBundle thread_bundle_;
DISALLOW_COPY_AND_ASSIGN(BrowserAccessibilityAuraLinuxTest);
};
BrowserAccessibilityAuraLinuxTest::BrowserAccessibilityAuraLinuxTest() {}
BrowserAccessibilityAuraLinuxTest::~BrowserAccessibilityAuraLinuxTest() {}
void BrowserAccessibilityAuraLinuxTest::SetUp() {}
TEST_F(BrowserAccessibilityAuraLinuxTest, TestSimpleAtkText) {
ui::AXNodeData root_data;
root_data.id = 1;
root_data.role = ax::mojom::Role::kStaticText;
root_data.SetName("\xE2\x98\xBA Multiple Words");
std::unique_ptr<BrowserAccessibilityManager> manager(
BrowserAccessibilityManager::Create(MakeAXTreeUpdate(root_data), nullptr,
new BrowserAccessibilityFactory()));
ui::AXPlatformNodeAuraLinux* root_obj =
ToBrowserAccessibilityAuraLinux(manager->GetRoot())->GetNode();
AtkObject* root_atk_object(root_obj->GetNativeViewAccessible());
ASSERT_TRUE(ATK_IS_OBJECT(root_atk_object));
ASSERT_TRUE(ATK_IS_TEXT(root_atk_object));
g_object_ref(root_atk_object);
AtkText* atk_text = ATK_TEXT(root_atk_object);
auto verify_atk_text_contents = [&](const char* expected_text,
int start_offset, int end_offset) {
gchar* text = atk_text_get_text(atk_text, start_offset, end_offset);
EXPECT_STREQ(expected_text, text);
g_free(text);
};
verify_atk_text_contents("\xE2\x98\xBA Multiple Words", 0, -1);
verify_atk_text_contents("Multiple Words", 2, -1);
verify_atk_text_contents("\xE2\x98\xBA", 0, 1);
EXPECT_EQ(16, atk_text_get_character_count(atk_text));
g_object_unref(root_atk_object);
manager.reset();
}
TEST_F(BrowserAccessibilityAuraLinuxTest, TestCompositeAtkText) {
const std::string text1_name = "One two three.";
const std::string text2_name = " Four five six.";
const int text_name_len = text1_name.length() + text2_name.length();
ui::AXNodeData text1;
text1.id = 11;
text1.role = ax::mojom::Role::kStaticText;
text1.SetName(text1_name);
ui::AXNodeData text2;
text2.id = 12;
text2.role = ax::mojom::Role::kStaticText;
text2.SetName(text2_name);
ui::AXNodeData root;
root.id = 1;
root.role = ax::mojom::Role::kRootWebArea;
root.child_ids.push_back(text1.id);
root.child_ids.push_back(text2.id);
std::unique_ptr<BrowserAccessibilityManager> manager(
BrowserAccessibilityManager::Create(MakeAXTreeUpdate(root, text1, text2),
nullptr,
new BrowserAccessibilityFactory()));
ui::AXPlatformNodeAuraLinux* root_obj =
ToBrowserAccessibilityAuraLinux(manager->GetRoot())->GetNode();
AtkObject* root_atk_object(root_obj->GetNativeViewAccessible());
ASSERT_TRUE(ATK_IS_OBJECT(root_atk_object));
ASSERT_TRUE(ATK_IS_TEXT(root_atk_object));
g_object_ref(root_atk_object);
AtkText* atk_text = ATK_TEXT(root_atk_object);
EXPECT_EQ(text_name_len, atk_text_get_character_count(atk_text));
gchar* text = atk_text_get_text(atk_text, 0, -1);
EXPECT_STREQ((text1_name + text2_name).c_str(), text);
g_free(text);
g_object_unref(root_atk_object);
manager.reset();
}
} // namespace content
......@@ -4,6 +4,8 @@
#include "content/browser/accessibility/browser_accessibility_manager_auralinux.h"
#include <vector>
#include "content/browser/accessibility/browser_accessibility_auralinux.h"
#include "content/common/accessibility_messages.h"
#include "ui/accessibility/platform/ax_platform_node_auralinux.h"
......@@ -72,4 +74,22 @@ void BrowserAccessibilityManagerAuraLinux::FireGeneratedEvent(
// Need to implement.
}
void BrowserAccessibilityManagerAuraLinux::OnAtomicUpdateFinished(
ui::AXTree* tree,
bool root_changed,
const std::vector<ui::AXTreeDelegate::Change>& changes) {
BrowserAccessibilityManager::OnAtomicUpdateFinished(tree, root_changed,
changes);
// This is the second step in what will be a three step process mirroring that
// used in BrowserAccessibilityManagerWin.
for (const auto& change : changes) {
const ui::AXNode* changed_node = change.node;
DCHECK(changed_node);
BrowserAccessibility* obj = GetFromAXNode(changed_node);
if (obj && obj->IsNative())
ToBrowserAccessibilityAuraLinux(obj)->GetNode()->UpdateHypertext();
}
}
} // namespace content
......@@ -5,6 +5,8 @@
#ifndef CONTENT_BROWSER_ACCESSIBILITY_BROWSER_ACCESSIBILITY_MANAGER_AURALINUX_H_
#define CONTENT_BROWSER_ACCESSIBILITY_BROWSER_ACCESSIBILITY_MANAGER_AURALINUX_H_
#include <vector>
#include "base/macros.h"
#include "content/browser/accessibility/browser_accessibility_manager.h"
......@@ -34,6 +36,13 @@ class CONTENT_EXPORT BrowserAccessibilityManagerAuraLinux
AtkObject* parent_object() { return parent_object_; }
protected:
// AXTreeDelegate methods.
void OnAtomicUpdateFinished(
ui::AXTree* tree,
bool root_changed,
const std::vector<ui::AXTreeDelegate::Change>& changes) override;
private:
AtkObject* parent_object_;
......
......@@ -1793,6 +1793,13 @@ test("content_unittests") {
sources += [ "../renderer/sandbox_mac_v2_unittest.mm" ]
}
if (use_atk) {
sources += [
"../browser/accessibility/browser_accessibility_auralinux_unittest.cc",
]
configs += [ "//build/config/linux/atk" ]
}
if (is_android || is_linux || is_mac || is_win || is_fuchsia) {
data = [
"$root_out_dir/content_shell.pak",
......
......@@ -920,6 +920,11 @@ int AXPlatformNodeAuraLinux::GetGTypeInterfaceMask() {
// for each object.
interface_mask |= 1 << ATK_ACTION_INTERFACE;
// TODO(accessibility): We should only expose this for some elements, but
// it might be better to do this after exposing the hypertext interface
// as well.
interface_mask |= 1 << ATK_TEXT_INTERFACE;
// Value Interface
int role = GetAtkRole();
if (role == ATK_ROLE_SCROLL_BAR || role == ATK_ROLE_SLIDER ||
......@@ -940,10 +945,6 @@ int AXPlatformNodeAuraLinux::GetGTypeInterfaceMask() {
if (role == ATK_ROLE_LINK)
interface_mask |= 1 << ATK_HYPERLINK_INTERFACE;
// Text interface
if (role == ATK_ROLE_TEXT)
interface_mask |= 1 << ATK_TEXT_INTERFACE;
return interface_mask;
}
......@@ -1621,6 +1622,10 @@ void AXPlatformNodeAuraLinux::NotifyAccessibilityEvent(
}
}
void AXPlatformNodeAuraLinux::UpdateHypertext() {
hypertext_ = ComputeHypertext();
}
int AXPlatformNodeAuraLinux::GetIndexInParent() {
if (!GetParent())
return -1;
......@@ -1804,7 +1809,10 @@ std::string AXPlatformNodeAuraLinux::GetTextForATK() {
if (IsPlainTextField())
return GetStringAttribute(ax::mojom::StringAttribute::kValue);
return AXPlatformNodeBase::GetText();
if (IsChildOfLeaf())
return AXPlatformNodeBase::GetText();
return base::UTF16ToUTF8(hypertext_.hypertext);
}
} // namespace ui
......@@ -88,7 +88,11 @@ class AXPlatformNodeAuraLinux : public AXPlatformNodeBase {
std::string GetTextForATK();
AX_EXPORT void UpdateHypertext();
protected:
AXHypertext hypertext_;
void AddAttributeToList(const char* name,
const char* value,
PlatformAttributeList* attributes) override;
......
......@@ -857,52 +857,4 @@ TEST_F(AXPlatformNodeAuraLinuxTest, TestAtkHyperlink) {
g_object_unref(root_obj);
}
//
// AtkText interface
//
TEST_F(AXPlatformNodeAuraLinuxTest, TestAtkText) {
AXNodeData root_data;
root_data.id = 1;
root_data.role = ax::mojom::Role::kStaticText;
Init(root_data);
AtkObject* root_atk_object(GetRootAtkObject());
ASSERT_TRUE(ATK_IS_OBJECT(root_atk_object));
ASSERT_TRUE(ATK_IS_TEXT(root_atk_object));
g_object_ref(root_atk_object);
AtkText* atk_text = ATK_TEXT(root_atk_object);
auto verify_atk_text_contents = [&](const char* expected_text,
int start_offset, int end_offset) {
gchar* text = atk_text_get_text(atk_text, start_offset, end_offset);
EXPECT_STREQ(expected_text, text);
g_free(text);
};
AXNode* root = GetRootNode();
SetStringAttributeOnNode(root, ax::mojom::StringAttribute::kName, "Text",
ax::mojom::Role::kStaticText);
verify_atk_text_contents("Text", 0, -1);
EXPECT_EQ(4, atk_text_get_character_count(atk_text));
SetStringAttributeOnNode(root, ax::mojom::StringAttribute::kName,
"Longer String", ax::mojom::Role::kStaticText);
verify_atk_text_contents("Longer String", 0, -1);
verify_atk_text_contents("Longer ", 0, 7);
verify_atk_text_contents("String", 7, -1);
EXPECT_EQ(13, atk_text_get_character_count(atk_text));
SetStringAttributeOnNode(root, ax::mojom::StringAttribute::kName,
"\xE2\x98\xBA", ax::mojom::Role::kStaticText);
verify_atk_text_contents("\xE2\x98\xBA", 0, -1);
verify_atk_text_contents("\xE2\x98\xBA", 0, 1);
EXPECT_EQ(1, atk_text_get_character_count(atk_text));
g_object_unref(root_atk_object);
}
} // namespace ui
......@@ -269,9 +269,9 @@ class AX_EXPORT AXPlatformNodeBase : public AXPlatformNode {
static void SanitizeStringAttribute(const std::string& input,
std::string* output);
// Compute the hypertext for this node to be exposed via IA2 (and ATK
// in the future). This method is responsible for properly embedding
// children using the special embedded element character.
// Compute the hypertext for this node to be exposed via IA2 and ATK This
// method is responsible for properly embedding children using the special
// embedded element character.
AXHypertext ComputeHypertext();
private:
......
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