Enforce valid role prior to calling AXNodeData::SetName
Callers are expected to set a valid role prior to calling SetName. We
check for Role::kNone (the role was explicitly changed to the
presentational role) but not Role::kUnknown (the role was never set /
AKA the default).
This commit adds Role::kUnknown to the existing DCHECK and sets
roles on several Views which were missing roles.
AX-Relnotes: n/a
Bug: 1348081
Change-Id: I7511fbdfdc78944978641d19e94f368dc6d72fcc
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3816142
Reviewed-by: Mitsuru Oshima <oshima@chromium.org>
Reviewed-by: David Tseng <dtseng@chromium.org>
Reviewed-by: Elly Fong-Jones <ellyjones@chromium.org>
Commit-Queue: Joanmarie Diggs <jdiggs@igalia.com>
Cr-Commit-Position: refs/heads/main@{#1045987}
diff --git a/ash/app_list/views/assistant/assistant_page_view.cc b/ash/app_list/views/assistant/assistant_page_view.cc
index 9518aeb..6881953 100644
--- a/ash/app_list/views/assistant/assistant_page_view.cc
+++ b/ash/app_list/views/assistant/assistant_page_view.cc
@@ -196,6 +196,9 @@
void AssistantPageView::GetAccessibleNodeData(ui::AXNodeData* node_data) {
View::GetAccessibleNodeData(node_data);
+
+ // A valid role must be set prior to setting the name.
+ node_data->role = ax::mojom::Role::kPane;
node_data->SetName(l10n_util::GetStringUTF16(IDS_ASH_ASSISTANT_WINDOW));
}
diff --git a/ash/app_list/views/search_result_list_view.cc b/ash/app_list/views/search_result_list_view.cc
index 84be004..9986e75 100644
--- a/ash/app_list/views/search_result_list_view.cc
+++ b/ash/app_list/views/search_result_list_view.cc
@@ -231,6 +231,8 @@
break;
}
+ // A valid role must be set prior to setting the name.
+ GetViewAccessibility().OverrideRole(ax::mojom::Role::kListBox);
GetViewAccessibility().OverrideName(l10n_util::GetStringFUTF16(
IDS_ASH_SEARCH_RESULT_CATEGORY_LABEL_ACCESSIBLE_NAME,
title_label_->GetText()));
diff --git a/ash/clipboard/views/clipboard_history_item_view.cc b/ash/clipboard/views/clipboard_history_item_view.cc
index a6dba46..f51ae3d 100644
--- a/ash/clipboard/views/clipboard_history_item_view.cc
+++ b/ash/clipboard/views/clipboard_history_item_view.cc
@@ -160,8 +160,6 @@
void ClipboardHistoryItemView::Init() {
SetFocusBehavior(views::View::FocusBehavior::ACCESSIBLE_ONLY);
- GetViewAccessibility().OverrideRole(ax::mojom::Role::kMenuItem);
-
SetLayoutManager(std::make_unique<views::FillLayout>());
// Ensures that MainButton is below any other child views.
@@ -269,6 +267,9 @@
}
void ClipboardHistoryItemView::GetAccessibleNodeData(ui::AXNodeData* data) {
+ // A valid role must be set in the AXNodeData prior to setting the name
+ // via AXNodeData::SetName.
+ data->role = ax::mojom::Role::kMenuItem;
data->SetName(GetAccessibleName());
}
diff --git a/ash/login/ui/media_controls_header_view.cc b/ash/login/ui/media_controls_header_view.cc
index 7cb96264..c26c23b 100644
--- a/ash/login/ui/media_controls_header_view.cc
+++ b/ash/login/ui/media_controls_header_view.cc
@@ -8,6 +8,7 @@
#include "ash/strings/grit/ash_strings.h"
#include "ash/style/ash_color_provider.h"
#include "components/vector_icons/vector_icons.h"
+#include "ui/accessibility/ax_enums.mojom.h"
#include "ui/accessibility/ax_node_data.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/gfx/color_utils.h"
@@ -117,6 +118,8 @@
}
void MediaControlsHeaderView::GetAccessibleNodeData(ui::AXNodeData* node_data) {
+ // A valid role must be set prior to setting the name.
+ node_data->role = ax::mojom::Role::kPane;
node_data->SetName(app_name_view_->GetText());
}
diff --git a/ash/shortcut_viewer/views/keyboard_shortcut_item_view.cc b/ash/shortcut_viewer/views/keyboard_shortcut_item_view.cc
index e4f1797..5deb212b 100644
--- a/ash/shortcut_viewer/views/keyboard_shortcut_item_view.cc
+++ b/ash/shortcut_viewer/views/keyboard_shortcut_item_view.cc
@@ -233,8 +233,8 @@
gfx::Insets::TLBR(kVerticalPadding, 0, kVerticalPadding, 0)));
// Use leaf list item role so that name is spoken by screen reader, but
- // redundant child label text is not also spoken.
- GetViewAccessibility().OverrideRole(ax::mojom::Role::kListItem);
+ // redundant child label text is not also spoken. (The role is set in
+ // GetAccessibleNodeData.)
GetViewAccessibility().OverrideIsLeaf(true);
accessible_name_ =
description_label_view_->GetText() + u", " + accessible_string;
@@ -242,6 +242,8 @@
void KeyboardShortcutItemView::GetAccessibleNodeData(
ui::AXNodeData* node_data) {
+ // A valid role must be set prior to setting the name.
+ node_data->role = ax::mojom::Role::kListItem;
node_data->SetName(accessible_name_);
}
diff --git a/ash/system/network/network_tray_view.cc b/ash/system/network/network_tray_view.cc
index c8ea6c2..2502c7a 100644
--- a/ash/system/network/network_tray_view.cc
+++ b/ash/system/network/network_tray_view.cc
@@ -52,6 +52,8 @@
}
void NetworkTrayView::GetAccessibleNodeData(ui::AXNodeData* node_data) {
+ // A valid role must be set prior to setting the name.
+ node_data->role = ax::mojom::Role::kImage;
node_data->SetName(accessible_name_);
node_data->SetDescription(accessible_description_);
}
diff --git a/ash/system/power/tray_power.cc b/ash/system/power/tray_power.cc
index d70caf7..f087eaf 100644
--- a/ash/system/power/tray_power.cc
+++ b/ash/system/power/tray_power.cc
@@ -22,6 +22,7 @@
#include "base/command_line.h"
#include "base/metrics/histogram.h"
#include "base/time/time.h"
+#include "ui/accessibility/ax_enums.mojom.h"
#include "ui/accessibility/ax_node_data.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/chromeos/devicetype_utils.h"
@@ -60,6 +61,8 @@
}
void PowerTrayView::GetAccessibleNodeData(ui::AXNodeData* node_data) {
+ // A valid role must be set prior to setting the name.
+ node_data->role = ax::mojom::Role::kImage;
node_data->SetName(accessible_name_);
}
diff --git a/chrome/browser/ash/accessibility/spoken_feedback_browsertest.cc b/chrome/browser/ash/accessibility/spoken_feedback_browsertest.cc
index 609b677f..b471d98 100644
--- a/chrome/browser/ash/accessibility/spoken_feedback_browsertest.cc
+++ b/chrome/browser/ash/accessibility/spoken_feedback_browsertest.cc
@@ -1026,8 +1026,9 @@
widget->Init(std::move(params));
views::View* view = new views::View();
- view->GetViewAccessibility().OverrideName("hello");
+ // A valid role must be set prior to setting the name.
view->GetViewAccessibility().OverrideRole(ax::mojom::Role::kButton);
+ view->GetViewAccessibility().OverrideName("hello");
view->SetFocusBehavior(views::View::FocusBehavior::ALWAYS);
widget->GetRootView()->AddChildView(view);
@@ -1103,8 +1104,9 @@
widget->Init(std::move(params));
views::View* view = new views::View();
- view->GetViewAccessibility().OverrideName("hello");
+ // A valid role must be set prior to setting the name.
view->GetViewAccessibility().OverrideRole(ax::mojom::Role::kButton);
+ view->GetViewAccessibility().OverrideName("hello");
view->SetFocusBehavior(views::View::FocusBehavior::ALWAYS);
widget->GetRootView()->AddChildView(view);
diff --git a/chrome/browser/ash/app_restore/arc_ghost_window_view.cc b/chrome/browser/ash/app_restore/arc_ghost_window_view.cc
index 35331439..28d3a81 100644
--- a/chrome/browser/ash/app_restore/arc_ghost_window_view.cc
+++ b/chrome/browser/ash/app_restore/arc_ghost_window_view.cc
@@ -44,6 +44,8 @@
}
void GetAccessibleNodeData(ui::AXNodeData* node_data) override {
+ // A valid role must be set prior to setting the name.
+ node_data->role = ax::mojom::Role::kProgressIndicator;
node_data->SetName(
l10n_util::GetStringUTF16(IDS_ARC_GHOST_WINDOW_APP_LAUNCHING_THROBBER));
}
diff --git a/chrome/browser/ash/arc/accessibility/drawer_layout_handler_unittest.cc b/chrome/browser/ash/arc/accessibility/drawer_layout_handler_unittest.cc
index ce4f4ffa..3b4969ab 100644
--- a/chrome/browser/ash/arc/accessibility/drawer_layout_handler_unittest.cc
+++ b/chrome/browser/ash/arc/accessibility/drawer_layout_handler_unittest.cc
@@ -154,10 +154,12 @@
ASSERT_EQ(2, create_result.value().first);
ui::AXNodeData data;
+ // A valid role must be set prior to calling SetName.
+ data.role = ax::mojom::Role::kMenu;
data.SetName("node description");
create_result.value().second->PostSerializeNode(&data);
- // Modifier doesn't override the name by an empty string.
+ // Modifier doesn't override the name by an empty string, or change the role.
ASSERT_EQ(ax::mojom::Role::kMenu, data.role);
ASSERT_EQ("node description",
data.GetStringAttribute(ax::mojom::StringAttribute::kName));
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_editor_view.cc b/chrome/browser/ui/views/bookmarks/bookmark_editor_view.cc
index f89cfe6b..ba372a4 100644
--- a/chrome/browser/ui/views/bookmarks/bookmark_editor_view.cc
+++ b/chrome/browser/ui/views/bookmarks/bookmark_editor_view.cc
@@ -134,6 +134,14 @@
void BookmarkEditorView::GetAccessibleNodeData(ui::AXNodeData* node_data) {
views::DialogDelegateView::GetAccessibleNodeData(node_data);
+
+ // TODO(crbug.com/1361263): Currently DialogDelegateView does not override
+ // GetAccessibleNodeData, thus the call above accomplishes nothing. We need
+ // this View to have a role before setting its name, but if we set it to
+ // dialog, we'll wind up with a dialog (this view) inside of a dialog
+ // (RootView). Note that both views also share the same accessible name.
+ // In the meantime, give it a generic role.
+ node_data->role = ax::mojom::Role::kPane;
node_data->SetName(l10n_util::GetStringUTF8(IDS_BOOKMARK_EDITOR_TITLE));
}
diff --git a/chrome/browser/ui/views/location_bar/icon_label_bubble_view.cc b/chrome/browser/ui/views/location_bar/icon_label_bubble_view.cc
index 03fdfde..97ad400 100644
--- a/chrome/browser/ui/views/location_bar/icon_label_bubble_view.cc
+++ b/chrome/browser/ui/views/location_bar/icon_label_bubble_view.cc
@@ -517,6 +517,12 @@
// instance anyway.
alert_virtual_view_->GetCustomData().RemoveState(
ax::mojom::State::kInvisible);
+
+ // A valid role must be set prior to setting the name.
+ // TODO(crbug.com/1361281): Consider using AnnounceText instead of a
+ // virtual view.
+ alert_virtual_view_->GetCustomData().role =
+ ax::mojom::Role::kGenericContainer;
alert_virtual_view_->GetCustomData().SetName(label);
alert_virtual_view_->NotifyAccessibilityEvent(ax::mojom::Event::kAlert);
}
diff --git a/ui/accessibility/ax_node_data.cc b/ui/accessibility/ax_node_data.cc
index 41b61b4..2500c1c 100644
--- a/ui/accessibility/ax_node_data.cc
+++ b/ui/accessibility/ax_node_data.cc
@@ -620,10 +620,12 @@
void AXNodeData::SetName(const std::string& name) {
// Elements with role='presentation' have Role::kNone. They should not be
- // named. This check is only relevant if the name is not empty.
+ // named. Objects with Role::kUnknown were never given a role. This check
+ // is only relevant if the name is not empty.
// TODO(accessibility): It would be nice to have a means to set the name
// and role at the same time to avoid this ordering requirement.
- DCHECK(role != ax::mojom::Role::kNone || name.empty())
+ DCHECK(name.empty() ||
+ (role != ax::mojom::Role::kNone && role != ax::mojom::Role::kUnknown))
<< "Cannot set name to '" << name << "' on class: '"
<< GetStringAttribute(ax::mojom::StringAttribute::kClassName)
<< "' because a valid role is needed to set the default NameFrom "
diff --git a/ui/accessibility/ax_node_data_unittest.cc b/ui/accessibility/ax_node_data_unittest.cc
index 2092adb..0a8c0349 100644
--- a/ui/accessibility/ax_node_data_unittest.cc
+++ b/ui/accessibility/ax_node_data_unittest.cc
@@ -366,6 +366,11 @@
TEST(AXNodeDataTest, SetName) {
AXNodeData data;
+ // SetName should not be called on a role of kUnknown. That role means the
+ // role has not yet been set, and we need a role to identify the NameFrom on
+ // objects where it has not been set. This is enforced by a DCHECK.
+ EXPECT_DCHECK_DEATH(data.SetName("no role yet"));
+
// SetName should not be called on a role of kNone. That role is used for
// presentational objects which should not be included in the accessibility
// tree. This is enforced by a DCHECK.