Commit b361075e authored by Martin Robinson's avatar Martin Robinson Committed by Commit Bot

Use the shared attribute code for ATK on Aura Linux

The newly shareable attribute code can be used for ATK on Aura Linux
because the attributes exposed should be exactly the same on this
platform. This change also adds some basic unit tests to ensure that
attributes are exposed properly through ATK.

Bug: 866612
Change-Id: Id46ab2108d9ead6ab88b5e172b6b25e615f47cca
Reviewed-on: https://chromium-review.googlesource.com/1156399
Commit-Queue: Martin Robinson <mrobinson@igalia.com>
Reviewed-by: default avatarDominic Mazzoni <dmazzoni@chromium.org>
Cr-Commit-Position: refs/heads/master@{#580164}
parent e63be647
......@@ -1591,13 +1591,10 @@ const gchar* AXPlatformNodeAuraLinux::GetDefaultActionName() {
ATK_AURALINUX_RETURN_STRING(base::UTF16ToUTF8(action_verb));
}
AtkAttributeSet* AXPlatformNodeAuraLinux::GetAtkAttributes() const {
AtkAttributeSet* atk_attributes = nullptr;
atk_attributes = AddIntAttributeToAtkAttributeSet(
atk_attributes, ax::mojom::IntAttribute::kHierarchicalLevel, "level");
return atk_attributes;
AtkAttributeSet* AXPlatformNodeAuraLinux::GetAtkAttributes() {
AtkAttributeSet* attribute_list = nullptr;
ComputeAttributes(&attribute_list);
return attribute_list;
}
// AtkDocumentHelpers
......@@ -1617,9 +1614,9 @@ const gchar* AXPlatformNodeAuraLinux::GetDocumentAttributeValue(
}
static AtkAttributeSet* PrependAtkAttributeToAtkAttributeSet(
AtkAttributeSet* attribute_set,
const char* name,
const char* value) {
const char* value,
AtkAttributeSet* attribute_set) {
AtkAttribute* attribute =
static_cast<AtkAttribute*>(g_malloc(sizeof(AtkAttribute)));
attribute->name = g_strdup(name);
......@@ -1636,7 +1633,7 @@ AtkAttributeSet* AXPlatformNodeAuraLinux::GetDocumentAttributes() const {
value = GetDocumentAttributeValue(doc_attributes[i]);
if (value) {
attribute_set = PrependAtkAttributeToAtkAttributeSet(
attribute_set, doc_attributes[i], value);
doc_attributes[i], value, attribute_set);
}
}
......@@ -1676,24 +1673,10 @@ void AXPlatformNodeAuraLinux::GetFloatAttributeInGValue(
}
}
AtkAttributeSet* AXPlatformNodeAuraLinux::AddIntAttributeToAtkAttributeSet(
AtkAttributeSet* attributes,
ax::mojom::IntAttribute attribute,
const char* atk_attribute) const {
int value;
if (GetIntAttribute(attribute, &value)) {
attributes = PrependAtkAttributeToAtkAttributeSet(
attributes, atk_attribute, base::IntToString(value).c_str());
}
return attributes;
}
void AXPlatformNodeAuraLinux::AddAttributeToList(
const char* name,
const char* value,
PlatformAttributeList* attributes) {
NOTREACHED();
void AXPlatformNodeAuraLinux::AddAttributeToList(const char* name,
const char* value,
AtkAttributeSet** attributes) {
*attributes = PrependAtkAttributeToAtkAttributeSet(name, value, *attributes);
}
} // namespace ui
......@@ -59,7 +59,7 @@ class AXPlatformNodeAuraLinux : public AXPlatformNodeBase {
bool GrabFocus();
bool DoDefaultAction();
const gchar* GetDefaultActionName();
AtkAttributeSet* GetAtkAttributes() const;
AtkAttributeSet* GetAtkAttributes();
void SetExtentsRelativeToAtkCoordinateType(
gint* x, gint* y, gint* width, gint* height,
......@@ -74,10 +74,6 @@ class AXPlatformNodeAuraLinux : public AXPlatformNodeBase {
// Misc helpers
void GetFloatAttributeInGValue(ax::mojom::FloatAttribute attr, GValue* value);
AtkAttributeSet* AddIntAttributeToAtkAttributeSet(
AtkAttributeSet* attributes,
ax::mojom::IntAttribute attribute,
const char* atk_attribute) const;
// Event helpers
void OnFocused();
......
......@@ -69,10 +69,93 @@ static void EnsureAtkObjectDoesNotHaveAttribute(
while (current) {
AtkAttribute* attribute = static_cast<AtkAttribute*>(current->data);
ASSERT_NE(0, strcmp(attribute_name, attribute->name));
current = current->next;
}
atk_attribute_set_free(attributes);
}
static void TestAtkObjectIntAttribute(
AXNode* ax_node,
AtkObject* atk_object,
ax::mojom::IntAttribute mojom_attribute,
const gchar* attribute_name,
base::Optional<ax::mojom::Role> role = base::nullopt) {
AXNodeData new_data = AXNodeData();
new_data.role = role.value_or(ax::mojom::Role::kApplication);
ax_node->SetData(new_data);
EnsureAtkObjectDoesNotHaveAttribute(atk_object, attribute_name);
std::pair<int, const char*> tests[] = {
std::make_pair(0, "0"), std::make_pair(1, "1"),
std::make_pair(2, "2"), std::make_pair(-100, "-100"),
std::make_pair(1000, "1000"),
};
for (unsigned i = 0; i < G_N_ELEMENTS(tests); i++) {
AXNodeData new_data = AXNodeData();
new_data.role = role.value_or(ax::mojom::Role::kApplication);
new_data.id = ax_node->data().id;
new_data.AddIntAttribute(mojom_attribute, tests[i].first);
ax_node->SetData(new_data);
EnsureAtkObjectHasAttributeWithValue(atk_object, attribute_name,
tests[i].second);
}
}
static void TestAtkObjectStringAttribute(
AXNode* ax_node,
AtkObject* atk_object,
ax::mojom::StringAttribute mojom_attribute,
const gchar* attribute_name,
base::Optional<ax::mojom::Role> role = base::nullopt) {
AXNodeData new_data = AXNodeData();
new_data.role = role.value_or(ax::mojom::Role::kApplication);
ax_node->SetData(new_data);
EnsureAtkObjectDoesNotHaveAttribute(atk_object, attribute_name);
const char* tests[] = {
"",
"a string with spaces"
"a string with , a comma",
"\xE2\x98\xBA", // The smiley emoji.
};
for (unsigned i = 0; i < G_N_ELEMENTS(tests); i++) {
AXNodeData new_data = AXNodeData();
new_data.role = role.value_or(ax::mojom::Role::kApplication);
new_data.id = ax_node->data().id;
new_data.AddStringAttribute(mojom_attribute, tests[i]);
ax_node->SetData(new_data);
EnsureAtkObjectHasAttributeWithValue(atk_object, attribute_name, tests[i]);
}
}
static void TestAtkObjectBoolAttribute(
AXNode* ax_node,
AtkObject* atk_object,
ax::mojom::BoolAttribute mojom_attribute,
const gchar* attribute_name,
base::Optional<ax::mojom::Role> role = base::nullopt) {
AXNodeData new_data = AXNodeData();
new_data.role = role.value_or(ax::mojom::Role::kApplication);
ax_node->SetData(new_data);
EnsureAtkObjectDoesNotHaveAttribute(atk_object, attribute_name);
new_data = AXNodeData();
new_data.role = role.value_or(ax::mojom::Role::kApplication);
new_data.id = ax_node->data().id;
new_data.AddBoolAttribute(mojom_attribute, true);
ax_node->SetData(new_data);
EnsureAtkObjectHasAttributeWithValue(atk_object, attribute_name, "true");
new_data = AXNodeData();
new_data.role = role.value_or(ax::mojom::Role::kApplication);
new_data.id = ax_node->data().id;
new_data.AddBoolAttribute(mojom_attribute, false);
ax_node->SetData(new_data);
EnsureAtkObjectHasAttributeWithValue(atk_object, attribute_name, "false");
}
//
// AtkObject tests
//
......@@ -403,7 +486,7 @@ TEST_F(AXPlatformNodeAuraLinuxTest, TestAtkObjectIndexInParent) {
g_object_unref(root_obj);
}
TEST_F(AXPlatformNodeAuraLinuxTest, TestAtkObjectAttributes) {
TEST_F(AXPlatformNodeAuraLinuxTest, TestAtkObjectStringAttributes) {
AXNodeData root_data;
root_data.id = 1;
......@@ -413,25 +496,104 @@ TEST_F(AXPlatformNodeAuraLinuxTest, TestAtkObjectAttributes) {
AtkObject* root_atk_object(AtkObjectFromNode(root_node));
ASSERT_TRUE(ATK_IS_OBJECT(root_atk_object));
g_object_ref(root_atk_object);
EnsureAtkObjectDoesNotHaveAttribute(root_atk_object, "level");
root_data = AXNodeData();
root_data.id = 1;
root_data.AddIntAttribute(ax::mojom::IntAttribute::kHierarchicalLevel, 1);
root_node->SetData(root_data);
EnsureAtkObjectHasAttributeWithValue(root_atk_object, "level", "1");
std::pair<ax::mojom::StringAttribute, const char*> tests[] = {
std::make_pair(ax::mojom::StringAttribute::kDisplay, "display"),
std::make_pair(ax::mojom::StringAttribute::kHtmlTag, "tag"),
std::make_pair(ax::mojom::StringAttribute::kRole, "xml-roles"),
std::make_pair(ax::mojom::StringAttribute::kPlaceholder, "placeholder"),
std::make_pair(ax::mojom::StringAttribute::kRoleDescription,
"roledescription"),
std::make_pair(ax::mojom::StringAttribute::kKeyShortcuts, "keyshortcuts"),
std::make_pair(ax::mojom::StringAttribute::kLiveStatus, "live"),
std::make_pair(ax::mojom::StringAttribute::kLiveRelevant, "relevant"),
std::make_pair(ax::mojom::StringAttribute::kContainerLiveStatus,
"container-live"),
std::make_pair(ax::mojom::StringAttribute::kContainerLiveRelevant,
"container-relevant"),
};
for (unsigned i = 0; i < G_N_ELEMENTS(tests); i++) {
TestAtkObjectStringAttribute(root_node, root_atk_object, tests[i].first,
tests[i].second);
}
root_data = AXNodeData();
g_object_unref(root_atk_object);
}
TEST_F(AXPlatformNodeAuraLinuxTest, TestAtkObjectBoolAttributes) {
AXNodeData root_data;
root_data.id = 1;
root_data.AddIntAttribute(ax::mojom::IntAttribute::kHierarchicalLevel, 2);
root_node->SetData(root_data);
EnsureAtkObjectHasAttributeWithValue(root_atk_object, "level", "2");
root_data = AXNodeData();
Init(root_data);
AXNode* root_node = GetRootNode();
AtkObject* root_atk_object(AtkObjectFromNode(root_node));
ASSERT_TRUE(ATK_IS_OBJECT(root_atk_object));
g_object_ref(root_atk_object);
std::pair<ax::mojom::BoolAttribute, const char*> tests[] = {
std::make_pair(ax::mojom::BoolAttribute::kLiveAtomic, "atomic"),
std::make_pair(ax::mojom::BoolAttribute::kBusy, "busy"),
std::make_pair(ax::mojom::BoolAttribute::kContainerLiveAtomic,
"container-atomic"),
std::make_pair(ax::mojom::BoolAttribute::kContainerLiveBusy,
"container-busy"),
};
for (unsigned i = 0; i < G_N_ELEMENTS(tests); i++) {
TestAtkObjectBoolAttribute(root_node, root_atk_object, tests[i].first,
tests[i].second);
}
g_object_unref(root_atk_object);
}
TEST_F(AXPlatformNodeAuraLinuxTest, TestAtkObjectIntAttributes) {
AXNodeData root_data;
root_data.id = 1;
root_data.AddIntAttribute(ax::mojom::IntAttribute::kHierarchicalLevel, 34);
root_node->SetData(root_data);
EnsureAtkObjectHasAttributeWithValue(root_atk_object, "level", "34");
Init(root_data);
AXNode* root_node = GetRootNode();
AtkObject* root_atk_object(AtkObjectFromNode(root_node));
ASSERT_TRUE(ATK_IS_OBJECT(root_atk_object));
g_object_ref(root_atk_object);
TestAtkObjectIntAttribute(root_node, root_atk_object,
ax::mojom::IntAttribute::kHierarchicalLevel,
"level");
TestAtkObjectIntAttribute(root_node, root_atk_object,
ax::mojom::IntAttribute::kSetSize, "setsize");
TestAtkObjectIntAttribute(root_node, root_atk_object,
ax::mojom::IntAttribute::kPosInSet, "posinset");
TestAtkObjectIntAttribute(root_node, root_atk_object,
ax::mojom::IntAttribute::kAriaColumnCount,
"colcount", ax::mojom::Role::kTable);
TestAtkObjectIntAttribute(root_node, root_atk_object,
ax::mojom::IntAttribute::kAriaColumnCount,
"colcount", ax::mojom::Role::kGrid);
TestAtkObjectIntAttribute(root_node, root_atk_object,
ax::mojom::IntAttribute::kAriaColumnCount,
"colcount", ax::mojom::Role::kTreeGrid);
TestAtkObjectIntAttribute(root_node, root_atk_object,
ax::mojom::IntAttribute::kAriaRowCount, "rowcount",
ax::mojom::Role::kTable);
TestAtkObjectIntAttribute(root_node, root_atk_object,
ax::mojom::IntAttribute::kAriaRowCount, "rowcount",
ax::mojom::Role::kGrid);
TestAtkObjectIntAttribute(root_node, root_atk_object,
ax::mojom::IntAttribute::kAriaRowCount, "rowcount",
ax::mojom::Role::kTreeGrid);
TestAtkObjectIntAttribute(root_node, root_atk_object,
ax::mojom::IntAttribute::kAriaCellColumnIndex,
"colindex", ax::mojom::Role::kCell);
TestAtkObjectIntAttribute(root_node, root_atk_object,
ax::mojom::IntAttribute::kAriaCellRowIndex,
"rowindex", ax::mojom::Role::kCell);
g_object_unref(root_atk_object);
}
......
......@@ -11,9 +11,14 @@
#include "base/macros.h"
#include "ui/accessibility/ax_enums.mojom.h"
#include "ui/accessibility/platform/ax_platform_node.h"
#include "ui/base/ui_features.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/native_widget_types.h"
#if BUILDFLAG(USE_ATK)
#include <atk/atk.h>
#endif
namespace ui {
struct AXNodeData;
......@@ -194,10 +199,15 @@ class AX_EXPORT AXPlatformNodeBase : public AXPlatformNode {
// Sets the text selection in this object if possible.
bool SetTextSelection(int start_offset, int end_offset);
#if BUILDFLAG(USE_ATK)
using PlatformAttributeList = AtkAttributeSet*;
#else
using PlatformAttributeList = std::vector<base::string16>;
#endif
// Compute the attributes exposed via platform accessibility objects and put
// them into an attribute list, |attributes|. Currently only used by
// IAccessible2 on Windows, but will soon be shared with other ports.
using PlatformAttributeList = std::vector<base::string16>;
// IAccessible2 on Windows and ATK on Aura Linux.
void ComputeAttributes(PlatformAttributeList* attributes);
// If the string attribute |attribute| is present, add its value as an
......
......@@ -55,6 +55,7 @@ buildflag_header("ui_features") {
"ENABLE_HIDPI=$enable_hidpi",
"ENABLE_MESSAGE_CENTER=$enable_message_center",
"ENABLE_MUS=$enable_mus",
"USE_ATK=$use_atk",
"USE_XKBCOMMON=$use_xkbcommon",
"MAC_VIEWS_BROWSER=$mac_views_browser",
"HAS_NATIVE_ACCESSIBILITY=$has_native_accessibility",
......
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