Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(268)

Unified Diff: ui/accessibility/platform/ax_platform_node_win.cc

Issue 2975413002: Move ia2_attributes handling to AXPlatformNodeWin. (Closed)
Patch Set: Suggestions from dmazzoni Created 3 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « ui/accessibility/platform/ax_platform_node_win.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: ui/accessibility/platform/ax_platform_node_win.cc
diff --git a/ui/accessibility/platform/ax_platform_node_win.cc b/ui/accessibility/platform/ax_platform_node_win.cc
index ca9ef23a165e5e247c421f5fa581a03b3787fa71..e7088f0dbbf419cbf213be47c2c856bbf4e9e9a6 100644
--- a/ui/accessibility/platform/ax_platform_node_win.cc
+++ b/ui/accessibility/platform/ax_platform_node_win.cc
@@ -204,6 +204,54 @@ AXPlatformNodeWin::AXPlatformNodeWin() {
AXPlatformNodeWin::~AXPlatformNodeWin() {
}
+// Static
+void AXPlatformNodeWin::SanitizeStringAttributeForIA2(
+ const base::string16& input,
+ base::string16* output) {
+ DCHECK(output);
+ // According to the IA2 Spec, these characters need to be escaped with a
+ // backslash: backslash, colon, comma, equals and semicolon.
+ // Note that backslash must be replaced first.
+ base::ReplaceChars(input, L"\\", L"\\\\", output);
+ base::ReplaceChars(*output, L":", L"\\:", output);
+ base::ReplaceChars(*output, L",", L"\\,", output);
+ base::ReplaceChars(*output, L"=", L"\\=", output);
+ base::ReplaceChars(*output, L";", L"\\;", output);
+}
+
+void AXPlatformNodeWin::StringAttributeToIA2(
+ std::vector<base::string16>& attributes,
+ ui::AXStringAttribute attribute,
+ const char* ia2_attr) {
+ base::string16 value;
+ if (GetString16Attribute(attribute, &value)) {
+ SanitizeStringAttributeForIA2(value, &value);
+ attributes.push_back(base::ASCIIToUTF16(ia2_attr) + L":" + value);
+ }
+}
+
+void AXPlatformNodeWin::BoolAttributeToIA2(
+ std::vector<base::string16>& attributes,
+ ui::AXBoolAttribute attribute,
+ const char* ia2_attr) {
+ bool value;
+ if (GetBoolAttribute(attribute, &value)) {
+ attributes.push_back((base::ASCIIToUTF16(ia2_attr) + L":") +
+ (value ? L"true" : L"false"));
+ }
+}
+
+void AXPlatformNodeWin::IntAttributeToIA2(
+ std::vector<base::string16>& attributes,
+ ui::AXIntAttribute attribute,
+ const char* ia2_attr) {
+ int value;
+ if (GetIntAttribute(attribute, &value)) {
+ attributes.push_back(base::ASCIIToUTF16(ia2_attr) + L":" +
+ base::IntToString16(value));
+ }
+}
+
//
// AXPlatformNodeBase implementation.
//
@@ -798,7 +846,7 @@ STDMETHODIMP AXPlatformNodeWin::put_accName(
STDMETHODIMP AXPlatformNodeWin::role(LONG* role) {
COM_OBJECT_VALIDATE_1_ARG(role);
- *role = IA2Role();
+ *role = ComputeIA2Role();
// If we didn't explicitly set the IAccessible2 role, make it the same
// as the MSAA role.
if (!*role)
@@ -808,7 +856,7 @@ STDMETHODIMP AXPlatformNodeWin::role(LONG* role) {
STDMETHODIMP AXPlatformNodeWin::get_states(AccessibleStates* states) {
COM_OBJECT_VALIDATE_1_ARG(states);
- *states = IA2State();
+ *states = ComputeIA2State();
return S_OK;
}
@@ -2220,7 +2268,7 @@ bool AXPlatformNodeWin::IsWebAreaForPresentationalIframe() {
return parent->GetData().role == ui::AX_ROLE_IFRAME_PRESENTATIONAL;
}
-int32_t AXPlatformNodeWin::IA2State() {
+int32_t AXPlatformNodeWin::ComputeIA2State() {
const AXNodeData& data = GetData();
int32_t ia2_state = IA2_STATE_OPAQUE;
@@ -2288,9 +2336,9 @@ int32_t AXPlatformNodeWin::IA2State() {
return ia2_state;
}
-// IA2Role() only returns a role if the MSAA role doesn't suffice,
+// ComputeIA2Role() only returns a role if the MSAA role doesn't suffice,
// otherwise this method returns 0. See AXPlatformNodeWin::role().
-int32_t AXPlatformNodeWin::IA2Role() {
+int32_t AXPlatformNodeWin::ComputeIA2Role() {
// If this is a web area for a presentational iframe, give it a role of
// something other than DOCUMENT so that the fact that it's a separate doc
// is not exposed to AT.
@@ -2426,6 +2474,215 @@ int32_t AXPlatformNodeWin::IA2Role() {
return ia2_role;
}
+std::vector<base::string16> AXPlatformNodeWin::ComputeIA2Attributes() {
+ std::vector<base::string16> result;
+ // Expose some HTLM and ARIA attributes in the IAccessible2 attributes string.
+ // "display", "tag", and "xml-roles" have somewhat unusual names for
+ // historical reasons. Aside from that virtually every ARIA attribute
+ // is exposed in a really straightforward way, i.e. "aria-foo" is exposed
+ // as "foo".
+ StringAttributeToIA2(result, ui::AX_ATTR_DISPLAY, "display");
+ StringAttributeToIA2(result, ui::AX_ATTR_HTML_TAG, "tag");
+ StringAttributeToIA2(result, ui::AX_ATTR_ROLE, "xml-roles");
+ StringAttributeToIA2(result, ui::AX_ATTR_PLACEHOLDER, "placeholder");
+
+ StringAttributeToIA2(result, ui::AX_ATTR_AUTO_COMPLETE, "autocomplete");
+ StringAttributeToIA2(result, ui::AX_ATTR_ROLE_DESCRIPTION, "roledescription");
+ StringAttributeToIA2(result, ui::AX_ATTR_KEY_SHORTCUTS, "keyshortcuts");
+
+ IntAttributeToIA2(result, ui::AX_ATTR_HIERARCHICAL_LEVEL, "level");
+ IntAttributeToIA2(result, ui::AX_ATTR_SET_SIZE, "setsize");
+ IntAttributeToIA2(result, ui::AX_ATTR_POS_IN_SET, "posinset");
+
+ if (HasIntAttribute(ui::AX_ATTR_CHECKED_STATE))
+ result.push_back(L"checkable:true");
+
+ // Expose live region attributes.
+ StringAttributeToIA2(result, ui::AX_ATTR_LIVE_STATUS, "live");
+ StringAttributeToIA2(result, ui::AX_ATTR_LIVE_RELEVANT, "relevant");
+ BoolAttributeToIA2(result, ui::AX_ATTR_LIVE_ATOMIC, "atomic");
+ BoolAttributeToIA2(result, ui::AX_ATTR_LIVE_BUSY, "busy");
+
+ // Expose container live region attributes.
+ StringAttributeToIA2(result, ui::AX_ATTR_CONTAINER_LIVE_STATUS,
+ "container-live");
+ StringAttributeToIA2(result, ui::AX_ATTR_CONTAINER_LIVE_RELEVANT,
+ "container-relevant");
+ BoolAttributeToIA2(result, ui::AX_ATTR_CONTAINER_LIVE_ATOMIC,
+ "container-atomic");
+ BoolAttributeToIA2(result, ui::AX_ATTR_CONTAINER_LIVE_BUSY, "container-busy");
+
+ // Expose the non-standard explicit-name IA2 attribute.
+ int name_from;
+ if (GetIntAttribute(ui::AX_ATTR_NAME_FROM, &name_from) &&
+ name_from != ui::AX_NAME_FROM_CONTENTS) {
+ result.push_back(L"explicit-name:true");
+ }
+
+ // Expose the aria-current attribute.
+ int32_t aria_current_state;
+ if (GetIntAttribute(ui::AX_ATTR_ARIA_CURRENT_STATE, &aria_current_state)) {
+ switch (static_cast<ui::AXAriaCurrentState>(aria_current_state)) {
+ case ui::AX_ARIA_CURRENT_STATE_NONE:
+ break;
+ case ui::AX_ARIA_CURRENT_STATE_FALSE:
+ result.push_back(L"current:false");
+ break;
+ case ui::AX_ARIA_CURRENT_STATE_TRUE:
+ result.push_back(L"current:true");
+ break;
+ case ui::AX_ARIA_CURRENT_STATE_PAGE:
+ result.push_back(L"current:page");
+ break;
+ case ui::AX_ARIA_CURRENT_STATE_STEP:
+ result.push_back(L"current:step");
+ break;
+ case ui::AX_ARIA_CURRENT_STATE_LOCATION:
+ result.push_back(L"current:location");
+ break;
+ case ui::AX_ARIA_CURRENT_STATE_DATE:
+ result.push_back(L"current:date");
+ break;
+ case ui::AX_ARIA_CURRENT_STATE_TIME:
+ result.push_back(L"current:time");
+ break;
+ }
+ }
+
+ // Expose table cell index.
+ if (ui::IsCellOrTableHeaderRole(GetData().role)) {
+ AXPlatformNodeBase* table = FromNativeViewAccessible(GetParent());
+
+ while (table && !ui::IsTableLikeRole(table->GetData().role))
+ table = FromNativeViewAccessible(table->GetParent());
+
+ if (table) {
+ const std::vector<int32_t>& unique_cell_ids =
+ table->GetIntListAttribute(ui::AX_ATTR_UNIQUE_CELL_IDS);
+ for (size_t i = 0; i < unique_cell_ids.size(); ++i) {
+ if (unique_cell_ids[i] == GetData().id) {
+ result.push_back(base::string16(L"table-cell-index:") +
+ base::IntToString16(static_cast<int>(i)));
+ }
+ }
+ }
+ }
+
+ // Expose aria-colcount and aria-rowcount in a table, grid or treegrid.
+ if (ui::IsTableLikeRole(GetData().role)) {
+ IntAttributeToIA2(result, ui::AX_ATTR_ARIA_COLUMN_COUNT, "colcount");
+ IntAttributeToIA2(result, ui::AX_ATTR_ARIA_ROW_COUNT, "rowcount");
+ }
+
+ // Expose aria-colindex and aria-rowindex in a cell or row.
+ if (ui::IsCellOrTableHeaderRole(GetData().role) ||
+ GetData().role == ui::AX_ROLE_ROW) {
+ if (GetData().role != ui::AX_ROLE_ROW)
+ IntAttributeToIA2(result, ui::AX_ATTR_ARIA_CELL_COLUMN_INDEX, "colindex");
+ IntAttributeToIA2(result, ui::AX_ATTR_ARIA_CELL_ROW_INDEX, "rowindex");
+ }
+
+ // Expose row or column header sort direction.
+ int32_t sort_direction;
+ if ((MSAARole() == ROLE_SYSTEM_COLUMNHEADER ||
+ MSAARole() == ROLE_SYSTEM_ROWHEADER) &&
+ GetIntAttribute(ui::AX_ATTR_SORT_DIRECTION, &sort_direction)) {
+ switch (static_cast<ui::AXSortDirection>(sort_direction)) {
+ case ui::AX_SORT_DIRECTION_NONE:
+ break;
+ case ui::AX_SORT_DIRECTION_UNSORTED:
+ result.push_back(L"sort:none");
+ break;
+ case ui::AX_SORT_DIRECTION_ASCENDING:
+ result.push_back(L"sort:ascending");
+ break;
+ case ui::AX_SORT_DIRECTION_DESCENDING:
+ result.push_back(L"sort:descending");
+ break;
+ case ui::AX_SORT_DIRECTION_OTHER:
+ result.push_back(L"sort:other");
+ break;
+ }
+ }
+
+ if (ui::IsCellOrTableHeaderRole(GetData().role)) {
+ // Expose colspan attribute.
+ base::string16 colspan;
+ if (GetData().GetHtmlAttribute("aria-colspan", &colspan)) {
+ SanitizeStringAttributeForIA2(colspan, &colspan);
+ result.push_back(L"colspan:" + colspan);
+ }
+ // Expose rowspan attribute.
+ base::string16 rowspan;
+ if (GetData().GetHtmlAttribute("aria-rowspan", &rowspan)) {
+ SanitizeStringAttributeForIA2(rowspan, &rowspan);
+ result.push_back(L"rowspan:" + rowspan);
+ }
+ }
+
+ // Expose slider value.
+ if (IsRangeValueSupported()) {
+ base::string16 value = GetRangeValueText();
+ SanitizeStringAttributeForIA2(value, &value);
+ result.push_back(L"valuetext:" + value);
+ }
+
+ // Expose dropeffect attribute.
+ base::string16 drop_effect;
+ if (GetData().GetHtmlAttribute("aria-dropeffect", &drop_effect)) {
+ SanitizeStringAttributeForIA2(drop_effect, &drop_effect);
+ result.push_back(L"dropeffect:" + drop_effect);
+ }
+
+ // Expose grabbed attribute.
+ base::string16 grabbed;
+ if (GetData().GetHtmlAttribute("aria-grabbed", &grabbed)) {
+ SanitizeStringAttributeForIA2(grabbed, &grabbed);
+ result.push_back(L"grabbed:" + grabbed);
+ }
+
+ // Expose class attribute.
+ base::string16 class_attr;
+ if (GetData().GetHtmlAttribute("class", &class_attr)) {
+ SanitizeStringAttributeForIA2(class_attr, &class_attr);
+ result.push_back(L"class:" + class_attr);
+ }
+
+ // Expose datetime attribute.
+ base::string16 datetime;
+ if (GetData().role == ui::AX_ROLE_TIME &&
+ GetData().GetHtmlAttribute("datetime", &datetime)) {
+ SanitizeStringAttributeForIA2(datetime, &datetime);
+ result.push_back(L"datetime:" + datetime);
+ }
+
+ // Expose id attribute.
+ base::string16 id;
+ if (GetData().GetHtmlAttribute("id", &id)) {
+ SanitizeStringAttributeForIA2(id, &id);
+ result.push_back(L"id:" + id);
+ }
+
+ // Expose src attribute.
+ base::string16 src;
+ if (GetData().role == ui::AX_ROLE_IMAGE &&
+ GetData().GetHtmlAttribute("src", &src)) {
+ SanitizeStringAttributeForIA2(src, &src);
+ result.push_back(L"src:" + src);
+ }
+
+ // Expose input-text type attribute.
+ base::string16 type;
+ base::string16 html_tag = GetString16Attribute(ui::AX_ATTR_HTML_TAG);
+ if (IsSimpleTextControl() && html_tag == L"input" &&
+ GetData().GetHtmlAttribute("type", &type)) {
+ SanitizeStringAttributeForIA2(type, &type);
+ result.push_back(L"text-input-type:" + type);
+ }
+
+ return result;
+}
+
bool AXPlatformNodeWin::ShouldNodeHaveReadonlyState(
const AXNodeData& data) const {
if (data.GetBoolAttribute(ui::AX_ATTR_ARIA_READONLY))
« no previous file with comments | « ui/accessibility/platform/ax_platform_node_win.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698