Commit 264fce03 authored by dougt's avatar dougt Committed by Commit Bot

Move ia2_attributes handling to AXPlatformNodeWin.

BUG=703369

Review-Url: https://codereview.chromium.org/2975413002
Cr-Commit-Position: refs/heads/master@{#487194}
parent 9c1d421f
...@@ -374,20 +374,6 @@ STDMETHODIMP BrowserAccessibilityComWin::get_accState(VARIANT var_id, ...@@ -374,20 +374,6 @@ STDMETHODIMP BrowserAccessibilityComWin::get_accState(VARIANT var_id,
return AXPlatformNodeWin::get_accState(var_id, state); return AXPlatformNodeWin::get_accState(var_id, state);
} }
bool BrowserAccessibilityComWin::IsRangeValueSupported() {
switch (MSAARole()) {
case ROLE_SYSTEM_PROGRESSBAR:
case ROLE_SYSTEM_SLIDER:
case ROLE_SYSTEM_SPINBUTTON:
case ROLE_SYSTEM_SCROLLBAR:
return true;
case ROLE_SYSTEM_SEPARATOR:
return owner()->HasState(ui::AX_STATE_FOCUSABLE);
default:
return false;
}
}
STDMETHODIMP BrowserAccessibilityComWin::get_accValue(VARIANT var_id, STDMETHODIMP BrowserAccessibilityComWin::get_accValue(VARIANT var_id,
BSTR* value) { BSTR* value) {
if (!owner()) if (!owner())
...@@ -2970,160 +2956,27 @@ void BrowserAccessibilityComWin::UpdateStep1ComputeWinAttributes() { ...@@ -2970,160 +2956,27 @@ void BrowserAccessibilityComWin::UpdateStep1ComputeWinAttributes() {
win_attributes_->ia_state = MSAAState(); win_attributes_->ia_state = MSAAState();
win_attributes_->role_name = base::UTF8ToUTF16(StringOverrideForMSAARole()); win_attributes_->role_name = base::UTF8ToUTF16(StringOverrideForMSAARole());
win_attributes_->ia2_role = IA2Role(); win_attributes_->ia2_role = ComputeIA2Role();
// If we didn't explicitly set the IAccessible2 role, make it the same // If we didn't explicitly set the IAccessible2 role, make it the same
// as the MSAA role. // as the MSAA role.
if (!win_attributes_->ia2_role) if (!win_attributes_->ia2_role)
win_attributes_->ia2_role = win_attributes_->ia_role; win_attributes_->ia2_role = win_attributes_->ia_role;
win_attributes_->ia2_state = IA2State(); win_attributes_->ia2_state = ComputeIA2State();
win_attributes_->ia2_attributes = ComputeIA2Attributes();
win_attributes_->ia2_attributes.clear();
// 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(ui::AX_ATTR_DISPLAY, "display");
StringAttributeToIA2(ui::AX_ATTR_HTML_TAG, "tag");
StringAttributeToIA2(ui::AX_ATTR_ROLE, "xml-roles");
StringAttributeToIA2(ui::AX_ATTR_AUTO_COMPLETE, "autocomplete");
StringAttributeToIA2(ui::AX_ATTR_ROLE_DESCRIPTION, "roledescription");
StringAttributeToIA2(ui::AX_ATTR_KEY_SHORTCUTS, "keyshortcuts");
IntAttributeToIA2(ui::AX_ATTR_HIERARCHICAL_LEVEL, "level");
IntAttributeToIA2(ui::AX_ATTR_SET_SIZE, "setsize");
IntAttributeToIA2(ui::AX_ATTR_POS_IN_SET, "posinset");
if (owner()->HasIntAttribute(ui::AX_ATTR_CHECKED_STATE))
win_attributes_->ia2_attributes.push_back(L"checkable:true");
// Expose live region attributes.
StringAttributeToIA2(ui::AX_ATTR_LIVE_STATUS, "live");
StringAttributeToIA2(ui::AX_ATTR_LIVE_RELEVANT, "relevant");
BoolAttributeToIA2(ui::AX_ATTR_LIVE_ATOMIC, "atomic");
BoolAttributeToIA2(ui::AX_ATTR_LIVE_BUSY, "busy");
// Expose container live region attributes.
StringAttributeToIA2(ui::AX_ATTR_CONTAINER_LIVE_STATUS, "container-live");
StringAttributeToIA2(ui::AX_ATTR_CONTAINER_LIVE_RELEVANT,
"container-relevant");
BoolAttributeToIA2(ui::AX_ATTR_CONTAINER_LIVE_ATOMIC, "container-atomic");
BoolAttributeToIA2(ui::AX_ATTR_CONTAINER_LIVE_BUSY, "container-busy");
// Expose the non-standard explicit-name IA2 attribute.
int name_from;
if (owner()->GetIntAttribute(ui::AX_ATTR_NAME_FROM, &name_from) &&
name_from != ui::AX_NAME_FROM_CONTENTS) {
win_attributes_->ia2_attributes.push_back(L"explicit-name:true");
}
// Expose the aria-current attribute.
int32_t aria_current_state;
if (owner()->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:
win_attributes_->ia2_attributes.push_back(L"current:false");
break;
case ui::AX_ARIA_CURRENT_STATE_TRUE:
win_attributes_->ia2_attributes.push_back(L"current:true");
break;
case ui::AX_ARIA_CURRENT_STATE_PAGE:
win_attributes_->ia2_attributes.push_back(L"current:page");
break;
case ui::AX_ARIA_CURRENT_STATE_STEP:
win_attributes_->ia2_attributes.push_back(L"current:step");
break;
case ui::AX_ARIA_CURRENT_STATE_LOCATION:
win_attributes_->ia2_attributes.push_back(L"current:location");
break;
case ui::AX_ARIA_CURRENT_STATE_DATE:
win_attributes_->ia2_attributes.push_back(L"current:date");
break;
case ui::AX_ARIA_CURRENT_STATE_TIME:
win_attributes_->ia2_attributes.push_back(L"current:time");
break;
}
}
// Expose table cell index.
if (ui::IsCellOrTableHeaderRole(owner()->GetRole())) {
BrowserAccessibilityWin* win_parent =
static_cast<BrowserAccessibilityWin*>(owner()->PlatformGetParent());
AXPlatformNodeBase* table = win_parent->GetCOM();
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] == owner()->GetId()) {
win_attributes_->ia2_attributes.push_back(
base::string16(L"table-cell-index:") + base::IntToString16(i));
}
}
}
}
// Expose aria-colcount and aria-rowcount in a table, grid or treegrid.
if (ui::IsTableLikeRole(owner()->GetRole())) {
IntAttributeToIA2(ui::AX_ATTR_ARIA_COLUMN_COUNT, "colcount");
IntAttributeToIA2(ui::AX_ATTR_ARIA_ROW_COUNT, "rowcount");
}
// Expose aria-colindex and aria-rowindex in a cell or row.
if (ui::IsCellOrTableHeaderRole(owner()->GetRole()) ||
owner()->GetRole() == ui::AX_ROLE_ROW) {
if (owner()->GetRole() != ui::AX_ROLE_ROW)
IntAttributeToIA2(ui::AX_ATTR_ARIA_CELL_COLUMN_INDEX, "colindex");
IntAttributeToIA2(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) &&
owner()->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:
win_attributes_->ia2_attributes.push_back(L"sort:none");
break;
case ui::AX_SORT_DIRECTION_ASCENDING:
win_attributes_->ia2_attributes.push_back(L"sort:ascending");
break;
case ui::AX_SORT_DIRECTION_DESCENDING:
win_attributes_->ia2_attributes.push_back(L"sort:descending");
break;
case ui::AX_SORT_DIRECTION_OTHER:
win_attributes_->ia2_attributes.push_back(L"sort:other");
break;
}
}
win_attributes_->name = owner()->GetString16Attribute(ui::AX_ATTR_NAME); win_attributes_->name = owner()->GetString16Attribute(ui::AX_ATTR_NAME);
win_attributes_->description = win_attributes_->description =
owner()->GetString16Attribute(ui::AX_ATTR_DESCRIPTION); owner()->GetString16Attribute(ui::AX_ATTR_DESCRIPTION);
StringAttributeToIA2(ui::AX_ATTR_PLACEHOLDER, "placeholder");
base::string16 value = owner()->GetValue(); base::string16 value = owner()->GetValue();
// Expose slider value. // Expose slider value.
if (IsRangeValueSupported()) { if (IsRangeValueSupported()) {
value = GetRangeValueText(); value = GetRangeValueText();
SanitizeStringAttributeForIA2(value, &value); } else if (owner()->IsDocument()) {
win_attributes_->ia2_attributes.push_back(L"valuetext:" + value);
} else {
// On Windows, the value of a document should be its url. // On Windows, the value of a document should be its url.
if (owner()->IsDocument()) {
value = base::UTF8ToUTF16(Manager()->GetTreeData().url); value = base::UTF8ToUTF16(Manager()->GetTreeData().url);
} }
// If this doesn't have a value and is linked then set its value to the url // If this doesn't have a value and is linked then set its value to the url
...@@ -3131,7 +2984,6 @@ void BrowserAccessibilityComWin::UpdateStep1ComputeWinAttributes() { ...@@ -3131,7 +2984,6 @@ void BrowserAccessibilityComWin::UpdateStep1ComputeWinAttributes() {
// destination. // destination.
if (value.empty() && (MSAAState() & STATE_SYSTEM_LINKED)) if (value.empty() && (MSAAState() & STATE_SYSTEM_LINKED))
value = owner()->GetString16Attribute(ui::AX_ATTR_URL); value = owner()->GetString16Attribute(ui::AX_ATTR_URL);
}
win_attributes_->value = value; win_attributes_->value = value;
...@@ -3162,8 +3014,6 @@ void BrowserAccessibilityComWin::UpdateStep1ComputeWinAttributes() { ...@@ -3162,8 +3014,6 @@ void BrowserAccessibilityComWin::UpdateStep1ComputeWinAttributes() {
int error_message_id; int error_message_id;
if (owner()->GetIntAttribute(ui::AX_ATTR_ERRORMESSAGE_ID, &error_message_id)) if (owner()->GetIntAttribute(ui::AX_ATTR_ERRORMESSAGE_ID, &error_message_id))
AddRelation(IA2_RELATION_ERROR_MESSAGE, error_message_id); AddRelation(IA2_RELATION_ERROR_MESSAGE, error_message_id);
UpdateRequiredAttributes();
} }
void BrowserAccessibilityComWin::UpdateStep2ComputeHypertext() { void BrowserAccessibilityComWin::UpdateStep2ComputeHypertext() {
...@@ -3614,36 +3464,6 @@ void BrowserAccessibilityComWin::SetIA2HypertextSelection(LONG start_offset, ...@@ -3614,36 +3464,6 @@ void BrowserAccessibilityComWin::SetIA2HypertextSelection(LONG start_offset,
end_position->AsTextPosition())); end_position->AsTextPosition()));
} }
void BrowserAccessibilityComWin::StringAttributeToIA2(
ui::AXStringAttribute attribute,
const char* ia2_attr) {
base::string16 value;
if (owner()->GetString16Attribute(attribute, &value)) {
SanitizeStringAttributeForIA2(value, &value);
win_attributes_->ia2_attributes.push_back(base::ASCIIToUTF16(ia2_attr) +
L":" + value);
}
}
void BrowserAccessibilityComWin::BoolAttributeToIA2(
ui::AXBoolAttribute attribute,
const char* ia2_attr) {
bool value;
if (owner()->GetBoolAttribute(attribute, &value)) {
win_attributes_->ia2_attributes.push_back(
(base::ASCIIToUTF16(ia2_attr) + L":") + (value ? L"true" : L"false"));
}
}
void BrowserAccessibilityComWin::IntAttributeToIA2(ui::AXIntAttribute attribute,
const char* ia2_attr) {
int value;
if (owner()->GetIntAttribute(attribute, &value)) {
win_attributes_->ia2_attributes.push_back(
base::ASCIIToUTF16(ia2_attr) + L":" + base::IntToString16(value));
}
}
bool BrowserAccessibilityComWin::IsHyperlink() const { bool BrowserAccessibilityComWin::IsHyperlink() const {
int32_t hyperlink_index = -1; int32_t hyperlink_index = -1;
auto* parent = owner()->PlatformGetParent(); auto* parent = owner()->PlatformGetParent();
...@@ -3893,16 +3713,6 @@ void BrowserAccessibilityComWin::GetSelectionOffsets(int* selection_start, ...@@ -3893,16 +3713,6 @@ void BrowserAccessibilityComWin::GetSelectionOffsets(int* selection_start,
++(*largest_offset); ++(*largest_offset);
} }
base::string16 BrowserAccessibilityComWin::GetRangeValueText() {
float fval;
base::string16 result = owner()->GetValue();
if (result.empty() && GetFloatAttribute(ui::AX_ATTR_VALUE_FOR_RANGE, &fval)) {
result = base::UTF8ToUTF16(base::DoubleToString(fval));
}
return result;
}
bool BrowserAccessibilityComWin::IsSameHypertextCharacter( bool BrowserAccessibilityComWin::IsSameHypertextCharacter(
size_t old_char_index, size_t old_char_index,
size_t new_char_index) { size_t new_char_index) {
...@@ -4264,76 +4074,6 @@ void BrowserAccessibilityComWin::RemoveTargetFromRelation( ...@@ -4264,76 +4074,6 @@ void BrowserAccessibilityComWin::RemoveTargetFromRelation(
} }
} }
void BrowserAccessibilityComWin::UpdateRequiredAttributes() {
if (ui::IsCellOrTableHeaderRole(owner()->GetRole())) {
// Expose colspan attribute.
base::string16 colspan;
if (owner()->GetHtmlAttribute("aria-colspan", &colspan)) {
SanitizeStringAttributeForIA2(colspan, &colspan);
win_attributes_->ia2_attributes.push_back(L"colspan:" + colspan);
}
// Expose rowspan attribute.
base::string16 rowspan;
if (owner()->GetHtmlAttribute("aria-rowspan", &rowspan)) {
SanitizeStringAttributeForIA2(rowspan, &rowspan);
win_attributes_->ia2_attributes.push_back(L"rowspan:" + rowspan);
}
}
// Expose dropeffect attribute.
base::string16 drop_effect;
if (owner()->GetHtmlAttribute("aria-dropeffect", &drop_effect)) {
SanitizeStringAttributeForIA2(drop_effect, &drop_effect);
win_attributes_->ia2_attributes.push_back(L"dropeffect:" + drop_effect);
}
// Expose grabbed attribute.
base::string16 grabbed;
if (owner()->GetHtmlAttribute("aria-grabbed", &grabbed)) {
SanitizeStringAttributeForIA2(grabbed, &grabbed);
win_attributes_->ia2_attributes.push_back(L"grabbed:" + grabbed);
}
// Expose class attribute.
base::string16 class_attr;
if (owner()->GetHtmlAttribute("class", &class_attr)) {
SanitizeStringAttributeForIA2(class_attr, &class_attr);
win_attributes_->ia2_attributes.push_back(L"class:" + class_attr);
}
// Expose datetime attribute.
base::string16 datetime;
if (owner()->GetRole() == ui::AX_ROLE_TIME &&
owner()->GetHtmlAttribute("datetime", &datetime)) {
SanitizeStringAttributeForIA2(datetime, &datetime);
win_attributes_->ia2_attributes.push_back(L"datetime:" + datetime);
}
// Expose id attribute.
base::string16 id;
if (owner()->GetHtmlAttribute("id", &id)) {
SanitizeStringAttributeForIA2(id, &id);
win_attributes_->ia2_attributes.push_back(L"id:" + id);
}
// Expose src attribute.
base::string16 src;
if (owner()->GetRole() == ui::AX_ROLE_IMAGE &&
owner()->GetHtmlAttribute("src", &src)) {
SanitizeStringAttributeForIA2(src, &src);
win_attributes_->ia2_attributes.push_back(L"src:" + src);
}
// Expose input-text type attribute.
base::string16 type;
base::string16 html_tag = owner()->GetString16Attribute(ui::AX_ATTR_HTML_TAG);
if (owner()->IsSimpleTextControl() && html_tag == L"input" &&
owner()->GetHtmlAttribute("type", &type)) {
SanitizeStringAttributeForIA2(type, &type);
win_attributes_->ia2_attributes.push_back(L"text-input-type:" + type);
}
}
void BrowserAccessibilityComWin::FireNativeEvent(LONG win_event_type) const { void BrowserAccessibilityComWin::FireNativeEvent(LONG win_event_type) const {
(new BrowserAccessibilityEventWin(BrowserAccessibilityEvent::FromTreeChange, (new BrowserAccessibilityEventWin(BrowserAccessibilityEvent::FromTreeChange,
ui::AX_EVENT_NONE, win_event_type, owner())) ui::AX_EVENT_NONE, win_event_type, owner()))
......
...@@ -788,19 +788,6 @@ class __declspec(uuid("562072fe-3390-43b1-9e2c-dd4118f5ac79")) ...@@ -788,19 +788,6 @@ class __declspec(uuid("562072fe-3390-43b1-9e2c-dd4118f5ac79"))
// Sets the selection given a start and end offset in IA2 Hypertext. // Sets the selection given a start and end offset in IA2 Hypertext.
void SetIA2HypertextSelection(LONG start_offset, LONG end_offset); void SetIA2HypertextSelection(LONG start_offset, LONG end_offset);
// If the string attribute |attribute| is present, add its value as an
// IAccessible2 attribute with the name |ia2_attr|.
void StringAttributeToIA2(ui::AXStringAttribute attribute,
const char* ia2_attr);
// If the bool attribute |attribute| is present, add its value as an
// IAccessible2 attribute with the name |ia2_attr|.
void BoolAttributeToIA2(ui::AXBoolAttribute attribute, const char* ia2_attr);
// If the int attribute |attribute| is present, add its value as an
// IAccessible2 attribute with the name |ia2_attr|.
void IntAttributeToIA2(ui::AXIntAttribute attribute, const char* ia2_attr);
// //
// Helper methods for IA2 hyperlinks. // Helper methods for IA2 hyperlinks.
// //
...@@ -850,13 +837,6 @@ class __declspec(uuid("562072fe-3390-43b1-9e2c-dd4118f5ac79")) ...@@ -850,13 +837,6 @@ class __declspec(uuid("562072fe-3390-43b1-9e2c-dd4118f5ac79"))
// selection.) // selection.)
void GetSelectionOffsets(int* selection_start, int* selection_end) const; void GetSelectionOffsets(int* selection_start, int* selection_end) const;
// Get the range value text, which might come from aria-valuetext or
// a floating-point value. This is different from the value string
// attribute used in input controls such as text boxes and combo boxes.
base::string16 GetRangeValueText();
// Return true for roles that support the value interface
bool IsRangeValueSupported();
bool IsSameHypertextCharacter(size_t old_char_index, size_t new_char_index); bool IsSameHypertextCharacter(size_t old_char_index, size_t new_char_index);
void ComputeHypertextRemovedAndInserted(int* start, void ComputeHypertextRemovedAndInserted(int* start,
...@@ -911,9 +891,6 @@ class __declspec(uuid("562072fe-3390-43b1-9e2c-dd4118f5ac79")) ...@@ -911,9 +891,6 @@ class __declspec(uuid("562072fe-3390-43b1-9e2c-dd4118f5ac79"))
void RemoveTargetFromRelation(const base::string16& relation_type, void RemoveTargetFromRelation(const base::string16& relation_type,
int target_id); int target_id);
// Updates object attributes of IA2 with html attributes.
void UpdateRequiredAttributes();
// Fire a Windows-specific accessibility event notification on this node. // Fire a Windows-specific accessibility event notification on this node.
void FireNativeEvent(LONG win_event_type) const; void FireNativeEvent(LONG win_event_type) const;
struct WinAttributes { struct WinAttributes {
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#include "ui/accessibility/platform/ax_platform_node_base.h" #include "ui/accessibility/platform/ax_platform_node_base.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h" #include "base/strings/utf_string_conversions.h"
#include "ui/accessibility/ax_action_data.h" #include "ui/accessibility/ax_action_data.h"
#include "ui/accessibility/ax_node_data.h" #include "ui/accessibility/ax_node_data.h"
...@@ -337,6 +338,16 @@ bool AXPlatformNodeBase::IsRangeValueSupported() const { ...@@ -337,6 +338,16 @@ bool AXPlatformNodeBase::IsRangeValueSupported() const {
} }
} }
base::string16 AXPlatformNodeBase::GetRangeValueText() {
float fval;
base::string16 value = GetString16Attribute(ui::AX_ATTR_VALUE);
if (value.empty() && GetFloatAttribute(ui::AX_ATTR_VALUE_FOR_RANGE, &fval)) {
value = base::UTF8ToUTF16(base::DoubleToString(fval));
}
return value;
}
AXPlatformNodeBase* AXPlatformNodeBase::GetTable() const { AXPlatformNodeBase* AXPlatformNodeBase::GetTable() const {
if (!delegate_) if (!delegate_)
return nullptr; return nullptr;
......
...@@ -130,6 +130,11 @@ class AX_EXPORT AXPlatformNodeBase : public AXPlatformNode { ...@@ -130,6 +130,11 @@ class AX_EXPORT AXPlatformNodeBase : public AXPlatformNode {
bool IsRichTextControl(); bool IsRichTextControl();
bool IsRangeValueSupported() const; bool IsRangeValueSupported() const;
// Get the range value text, which might come from aria-valuetext or
// a floating-point value. This is different from the value string
// attribute used in input controls such as text boxes and combo boxes.
base::string16 GetRangeValueText();
// |GetInnerText| recursively includes all the text from descendants such as // |GetInnerText| recursively includes all the text from descendants such as
// text found in any embedded object. // text found in any embedded object.
base::string16 GetInnerText(); base::string16 GetInnerText();
......
...@@ -204,6 +204,54 @@ AXPlatformNodeWin::AXPlatformNodeWin() { ...@@ -204,6 +204,54 @@ AXPlatformNodeWin::AXPlatformNodeWin() {
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. // AXPlatformNodeBase implementation.
// //
...@@ -821,7 +869,7 @@ STDMETHODIMP AXPlatformNodeWin::role(LONG* role) { ...@@ -821,7 +869,7 @@ STDMETHODIMP AXPlatformNodeWin::role(LONG* role) {
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_ROLE); WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_ROLE);
COM_OBJECT_VALIDATE_1_ARG(role); COM_OBJECT_VALIDATE_1_ARG(role);
*role = IA2Role(); *role = ComputeIA2Role();
// If we didn't explicitly set the IAccessible2 role, make it the same // If we didn't explicitly set the IAccessible2 role, make it the same
// as the MSAA role. // as the MSAA role.
if (!*role) if (!*role)
...@@ -832,7 +880,7 @@ STDMETHODIMP AXPlatformNodeWin::role(LONG* role) { ...@@ -832,7 +880,7 @@ STDMETHODIMP AXPlatformNodeWin::role(LONG* role) {
STDMETHODIMP AXPlatformNodeWin::get_states(AccessibleStates* states) { STDMETHODIMP AXPlatformNodeWin::get_states(AccessibleStates* states) {
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_STATES); WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_STATES);
COM_OBJECT_VALIDATE_1_ARG(states); COM_OBJECT_VALIDATE_1_ARG(states);
*states = IA2State(); *states = ComputeIA2State();
return S_OK; return S_OK;
} }
...@@ -2259,7 +2307,7 @@ bool AXPlatformNodeWin::IsWebAreaForPresentationalIframe() { ...@@ -2259,7 +2307,7 @@ bool AXPlatformNodeWin::IsWebAreaForPresentationalIframe() {
return parent->GetData().role == ui::AX_ROLE_IFRAME_PRESENTATIONAL; return parent->GetData().role == ui::AX_ROLE_IFRAME_PRESENTATIONAL;
} }
int32_t AXPlatformNodeWin::IA2State() { int32_t AXPlatformNodeWin::ComputeIA2State() {
const AXNodeData& data = GetData(); const AXNodeData& data = GetData();
int32_t ia2_state = IA2_STATE_OPAQUE; int32_t ia2_state = IA2_STATE_OPAQUE;
...@@ -2327,9 +2375,9 @@ int32_t AXPlatformNodeWin::IA2State() { ...@@ -2327,9 +2375,9 @@ int32_t AXPlatformNodeWin::IA2State() {
return ia2_state; 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(). // 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 // 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 // something other than DOCUMENT so that the fact that it's a separate doc
// is not exposed to AT. // is not exposed to AT.
...@@ -2465,6 +2513,215 @@ int32_t AXPlatformNodeWin::IA2Role() { ...@@ -2465,6 +2513,215 @@ int32_t AXPlatformNodeWin::IA2Role() {
return ia2_role; 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( bool AXPlatformNodeWin::ShouldNodeHaveReadonlyState(
const AXNodeData& data) const { const AXNodeData& data) const {
if (data.GetBoolAttribute(ui::AX_ATTR_ARIA_READONLY)) if (data.GetBoolAttribute(ui::AX_ATTR_ARIA_READONLY))
......
...@@ -593,9 +593,11 @@ class AX_EXPORT __declspec(uuid("26f5641a-246d-457b-a96d-07f3fae6acf2")) ...@@ -593,9 +593,11 @@ class AX_EXPORT __declspec(uuid("26f5641a-246d-457b-a96d-07f3fae6acf2"))
int MSAARole(); int MSAARole();
std::string StringOverrideForMSAARole(); std::string StringOverrideForMSAARole();
int32_t IA2State(); int32_t ComputeIA2State();
int32_t IA2Role(); int32_t ComputeIA2Role();
std::vector<base::string16> ComputeIA2Attributes();
// AXPlatformNodeBase overrides. // AXPlatformNodeBase overrides.
void Dispose() override; void Dispose() override;
...@@ -610,6 +612,32 @@ class AX_EXPORT __declspec(uuid("26f5641a-246d-457b-a96d-07f3fae6acf2")) ...@@ -610,6 +612,32 @@ class AX_EXPORT __declspec(uuid("26f5641a-246d-457b-a96d-07f3fae6acf2"))
ui::AXStringAttribute attribute, ui::AXStringAttribute attribute,
BSTR* value_bstr) const; BSTR* value_bstr) const;
// Escapes characters in string attributes as required by the IA2 Spec.
// It's okay for input to be the same as output.
static void SanitizeStringAttributeForIA2(const base::string16& input,
base::string16* output);
// Sets the selection given a start and end offset in IA2 Hypertext.
void SetIA2HypertextSelection(LONG start_offset, LONG end_offset);
// If the string attribute |attribute| is present, add its value as an
// IAccessible2 attribute with the name |ia2_attr|.
void StringAttributeToIA2(std::vector<base::string16>& attributes,
ui::AXStringAttribute attribute,
const char* ia2_attr);
// If the bool attribute |attribute| is present, add its value as an
// IAccessible2 attribute with the name |ia2_attr|.
void BoolAttributeToIA2(std::vector<base::string16>& attributes,
ui::AXBoolAttribute attribute,
const char* ia2_attr);
// If the int attribute |attribute| is present, add its value as an
// IAccessible2 attribute with the name |ia2_attr|.
void IntAttributeToIA2(std::vector<base::string16>& attributes,
ui::AXIntAttribute attribute,
const char* ia2_attr);
void AddAlertTarget(); void AddAlertTarget();
void RemoveAlertTarget(); void RemoveAlertTarget();
......
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