Commit b6397cf5 authored by David Tseng's avatar David Tseng Committed by Commit Bot

Reland: Use AXNode::GetSetSize/AXNode::GetPosInSet unconditionally

Fixed issue by only using the AXTree::GetPosInSet/AXTree::GetSetSize heuristics if they provide a nonzero answer. Otherwise, fall back to raw attributes.
This also exposes pos in set/set size if they are set without doing a role check as some renderers like ARC++ have no such restrictions.

TBR=dmazzoni@chromium.org
Original change description:
This moves ChromeVox to use AXNode::GetSetSize and AXNode::GetPosInSet through their automation bindings.

One issue is fixed:

In AXTree:PopulateOrderedSetItems, an assumption is made that the first child node of the ordered set node, should determine the hierarchical level of the current layer of items.

Unfortunately, for trees like:
tree
  static text
  tree item
  ...

this hueristic fails. See output_test.extjs::NestedLists.

Test: browser_tests --gtest_filter=ChromeVoxOutput*.*
Change-Id: I54911673215e245808a88fab07275a83c2d7109d
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1536470Reviewed-by: default avatarDavid Tseng <dtseng@chromium.org>
Reviewed-by: default avatarDominic Mazzoni <dmazzoni@chromium.org>
Reviewed-by: default avatarAkihiro Ota <akihiroota@chromium.org>
Commit-Queue: David Tseng <dtseng@chromium.org>
Cr-Original-Commit-Position: refs/heads/master@{#645669}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1560015
Cr-Commit-Position: refs/heads/master@{#649245}
parent 4aa85f1c
...@@ -464,13 +464,12 @@ Output.RULES = { ...@@ -464,13 +464,12 @@ Output.RULES = {
$if($inPageLinkTarget, @internal_link, $role) $description`, $if($inPageLinkTarget, @internal_link, $role) $description`,
}, },
list: { list: {
enter: `$role @@list_with_items($countChildren(listItem))`, enter: `$role @@list_with_items($setSize)`,
speak: `$nameFromNode $descendants $role speak: `$nameFromNode $descendants $role
@@list_with_items($countChildren(listItem)) $description $state` @@list_with_items($setSize) $description $state`
}, },
listBox: { listBox: {
enter: `$nameFromNode enter: `$nameFromNode $role @@list_with_items($setSize)
$role @@list_with_items($countChildren(listBoxOption))
$restriction $description` $restriction $description`
}, },
listBoxOption: { listBoxOption: {
...@@ -485,29 +484,23 @@ Output.RULES = { ...@@ -485,29 +484,23 @@ Output.RULES = {
menu: { menu: {
enter: `$name $role `, enter: `$name $role `,
speak: `$name $node(activeDescendant) speak: `$name $node(activeDescendant)
$role @@list_with_items( $role @@list_with_items($setSize) $description $state $restriction`
$countChildren(menuItem, menuItemCheckBox, menuItemRadio))
$description $state $restriction`
}, },
menuItem: { menuItem: {
speak: `$name $role $if($hasPopup, @has_submenu) speak: `$name $role $if($hasPopup, @has_submenu)
@describe_index($if($posInSet, $posInSet, $indexInParent(menuItem, menuItemCheckBox, menuItemRadio)), @describe_index($posInSet, $setSize) $description $state $restriction`
$if($setSize, $setSize, $parentChildCount(menuItem, menuItemCheckBox, menuItemRadio)))
$description $state $restriction`
}, },
menuItemCheckBox: { menuItemCheckBox: {
speak: `$if($checked, $earcon(CHECK_ON), $earcon(CHECK_OFF)) speak: `$if($checked, $earcon(CHECK_ON), $earcon(CHECK_OFF))
$name $role $checked $state $restriction $description $name $role $checked $state $restriction $description
@describe_index($if($posInSet, $posInSet, $indexInParent(menuItem, menuItemCheckBox, menuItemRadio)), @describe_index($posInSet, $setSize)`
$if($setSize, $setSize, $parentChildCount(menuItem, menuItemCheckBox, menuItemRadio))) `
}, },
menuItemRadio: { menuItemRadio: {
speak: `$if($checked, $earcon(CHECK_ON), $earcon(CHECK_OFF)) speak: `$if($checked, $earcon(CHECK_ON), $earcon(CHECK_OFF))
$if($checked, @describe_radio_selected($name), $if($checked, @describe_radio_selected($name),
@describe_radio_unselected($name)) $state $roleDescription @describe_radio_unselected($name)) $state $roleDescription
$restriction $description $restriction $description
@describe_index($if($posInSet, $posInSet, $indexInParent(menuItem, menuItemCheckBox, menuItemRadio)), @describe_index($posInSet, $setSize)`
$if($setSize, $setSize, $parentChildCount(menuItem, menuItemCheckBox, menuItemRadio))) `
}, },
menuListOption: { menuListOption: {
speak: `$name $role @describe_index($posInSet, $setSize) $state speak: `$name $role @describe_index($posInSet, $setSize) $state
...@@ -578,10 +571,7 @@ Output.RULES = { ...@@ -578,10 +571,7 @@ Output.RULES = {
$name $role $pressed $description $state $restriction` $name $role $pressed $description $state $restriction`
}, },
toolbar: {enter: `$name $role $description $restriction`}, toolbar: {enter: `$name $role $description $restriction`},
tree: { tree: {enter: `$name $role @@list_with_items($setSize) $restriction`},
enter: `$name $role @@list_with_items($countChildren(treeItem))
$restriction`
},
treeItem: { treeItem: {
enter: `$role $expanded $collapsed $restriction enter: `$role $expanded $collapsed $restriction
@describe_index($posInSet, $setSize) @describe_index($posInSet, $setSize)
...@@ -1321,25 +1311,6 @@ Output.prototype = { ...@@ -1321,25 +1311,6 @@ Output.prototype = {
this.append_(buff, String(count)); this.append_(buff, String(count));
ruleStr.writeTokenWithValue(token, String(count)); ruleStr.writeTokenWithValue(token, String(count));
} }
} else if (token == 'parentChildCount') {
if (node.parent) {
options.annotation.push(token);
var roles;
if (tree.firstChild) {
roles = this.createRoles_(tree);
} else {
roles = new Set();
roles.add(node.role);
}
var count = node.parent.children
.filter(function(child) {
return roles.has(child.role);
})
.length;
this.append_(buff, String(count));
ruleStr.writeTokenWithValue(token, String(count));
}
} else if (token == 'restriction') { } else if (token == 'restriction') {
var msg = Output.RESTRICTION_STATE_MAP[node.restriction]; var msg = Output.RESTRICTION_STATE_MAP[node.restriction];
if (msg) { if (msg) {
...@@ -1590,13 +1561,9 @@ Output.prototype = { ...@@ -1590,13 +1561,9 @@ Output.prototype = {
this.format_(node, '$indexInParent', buff, ruleStr); this.format_(node, '$indexInParent', buff, ruleStr);
} }
} else if (token == 'setSize') { } else if (token == 'setSize') {
if (node.setSize !== undefined) { var size = node.setSize ? node.setSize : 0;
this.append_(buff, String(node.setSize)); this.append_(buff, String(size));
ruleStr.writeTokenWithValue(token, String(node.setSize)); ruleStr.writeTokenWithValue(token, String(node.setSize));
} else {
ruleStr.writeToken(token);
this.format_(node, '$parentChildCount', buff, ruleStr);
}
} else if (tree.firstChild) { } else if (tree.firstChild) {
// Custom functions. // Custom functions.
if (token == 'if') { if (token == 'if') {
...@@ -1630,16 +1597,6 @@ Output.prototype = { ...@@ -1630,16 +1597,6 @@ Output.prototype = {
tree.firstChild.value, node.location || undefined)); tree.firstChild.value, node.location || undefined));
this.append_(buff, '', options); this.append_(buff, '', options);
ruleStr.writeTokenWithValue(token, tree.firstChild.value); ruleStr.writeTokenWithValue(token, tree.firstChild.value);
} else if (token == 'countChildren') {
var roles = this.createRoles_(tree);
var count = node.children
.filter(function(e) {
return roles.has(e.role);
})
.length;
this.append_(buff, String(count));
ruleStr.writeTokenWithValue(token, String(count));
} }
} }
} else if (prefix == '@') { } else if (prefix == '@') {
......
...@@ -818,14 +818,12 @@ void AutomationInternalCustomBindings::AddRoutes() { ...@@ -818,14 +818,12 @@ void AutomationInternalCustomBindings::AddRoutes() {
ui::ParseIntAttribute(attribute_name.c_str()); ui::ParseIntAttribute(attribute_name.c_str());
int attr_value; int attr_value;
if (attribute == ax::mojom::IntAttribute::kPosInSet) { if (attribute == ax::mojom::IntAttribute::kPosInSet &&
node->GetPosInSet()) {
attr_value = node->GetPosInSet(); attr_value = node->GetPosInSet();
if (attr_value == 0) } else if (attribute == ax::mojom::IntAttribute::kSetSize &&
return; node->GetSetSize()) {
} else if (attribute == ax::mojom::IntAttribute::kSetSize) {
attr_value = node->GetSetSize(); attr_value = node->GetSetSize();
if (attr_value == 0)
return;
} else if (!node->data().GetIntAttribute(attribute, &attr_value)) { } else if (!node->data().GetIntAttribute(attribute, &attr_value)) {
return; return;
} }
......
...@@ -946,13 +946,16 @@ void AXTree::PopulateOrderedSetItems(const AXNode* ordered_set, ...@@ -946,13 +946,16 @@ void AXTree::PopulateOrderedSetItems(const AXNode* ordered_set,
int original_level = original_node.GetIntAttribute( int original_level = original_node.GetIntAttribute(
ax::mojom::IntAttribute::kHierarchicalLevel); ax::mojom::IntAttribute::kHierarchicalLevel);
// If original node is ordered set, then set its hierarchical level equal to // If original node is ordered set, then set its hierarchical level equal to
// its first child to ensure the items vector gets populated. // its first child that sets a hierarchical level, if any.
// This is due to ordered sets having a hierarchical level of 0, while their if (ordered_set == &original_node) {
// nodes have non-zero hierarchical values. for (int32_t i = 0; i < original_node.GetUnignoredChildCount(); ++i) {
if ((ordered_set == &original_node) && int32_t level =
ordered_set->GetUnignoredChildAtIndex(0)) { original_node.GetUnignoredChildAtIndex(i)->GetIntAttribute(
original_level = ordered_set->GetUnignoredChildAtIndex(0)->GetIntAttribute(
ax::mojom::IntAttribute::kHierarchicalLevel); ax::mojom::IntAttribute::kHierarchicalLevel);
if (level)
original_level =
original_level ? std::min(level, original_level) : level;
}
} }
int original_node_index = original_node.GetUnignoredIndexInParent(); int original_node_index = original_node.GetUnignoredIndexInParent();
bool node_is_radio_button = bool node_is_radio_button =
......
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