Commit 71c3bc8c authored by Nektarios Paisios's avatar Nektarios Paisios Committed by Commit Bot

Exposes both pressed and checked for switches on Win instead of only checked

On Win, ARIA switches are equivalent to toggle buttons.
We need to expose both the pressed and checked states instead of only checked.
This fixes NVDA's announcement of the toggling of switches to on, whilst minimally affecting Jaws.
Jaws now reads "<switch name> on pressed" instead of "<switche name> on".
R=aleventhal@chromium.org, suproteem@chromium.org
Bug: 844021
Tested: manually with Jaws and NVDA, browser tests


Change-Id: I9ce4936002bf1a3cf0b99c73a73385c0a32ff3fc
Reviewed-on: https://chromium-review.googlesource.com/1101849
Commit-Queue: Nektarios Paisios <nektar@chromium.org>
Reviewed-by: default avatarAaron Leventhal <aleventhal@chromium.org>
Reviewed-by: default avatarNektarios Paisios <nektar@chromium.org>
Cr-Commit-Position: refs/heads/master@{#569937}
parent 5e67f216
android.webkit.WebView focusable focused scrollable
++android.widget.CheckBox role_description='switch' checkable clickable name='Switch1'
++android.widget.CheckBox role_description='switch' checkable checked clickable name='Switch2'
++android.widget.CheckBox role_description='switch' checkable clickable name='Switch2'
++android.widget.CheckBox role_description='switch' checkable checked clickable name='Switch3'
++android.widget.CheckBox role_description='switch' checkable checked clickable name='Switch4'
rootWebArea
++switch name='Switch1' checkedState=false
++switch name='Switch2' checkedState=true
++switch name='Switch3' checkedState=true
\ No newline at end of file
++switch name='Switch2' checkedState=false
++switch name='Switch3' checkedState=true
++switch name='Switch4' checkedState=true
AXWebArea AXRoleDescription='HTML content'
++AXCheckBox AXSubrole=AXSwitch AXRoleDescription='switch' AXTitle='Switch1' AXValue='0'
++AXCheckBox AXSubrole=AXSwitch AXRoleDescription='switch' AXTitle='Switch2' AXValue='1'
++AXCheckBox AXSubrole=AXSwitch AXRoleDescription='switch' AXTitle='Switch2' AXValue='0'
++AXCheckBox AXSubrole=AXSwitch AXRoleDescription='switch' AXTitle='Switch3' AXValue='1'
++AXCheckBox AXSubrole=AXSwitch AXRoleDescription='switch' AXTitle='Switch4' AXValue='1'
ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE ia2_hypertext='<obj0><obj1><obj2>'
ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE ia2_hypertext='<obj0><obj1><obj2><obj3>'
++IA2_ROLE_TOGGLE_BUTTON name='Switch1' IA2_STATE_CHECKABLE xml-roles:switch checkable:true ia2_hypertext='Switch1'
++IA2_ROLE_TOGGLE_BUTTON name='Switch2' CHECKED IA2_STATE_CHECKABLE xml-roles:switch checkable:true ia2_hypertext='Switch2'
++IA2_ROLE_TOGGLE_BUTTON name='Switch3' CHECKED IA2_STATE_CHECKABLE xml-roles:switch checkable:true ia2_hypertext='Switch3'
\ No newline at end of file
++IA2_ROLE_TOGGLE_BUTTON name='Switch2' IA2_STATE_CHECKABLE xml-roles:switch checkable:true ia2_hypertext='Switch2'
++IA2_ROLE_TOGGLE_BUTTON name='Switch3' PRESSED CHECKED IA2_STATE_CHECKABLE xml-roles:switch checkable:true ia2_hypertext='Switch3'
++IA2_ROLE_TOGGLE_BUTTON name='Switch4' PRESSED CHECKED IA2_STATE_CHECKABLE xml-roles:switch checkable:true ia2_hypertext='Switch4'
......@@ -10,7 +10,9 @@
<html>
<body>
<div role="switch">Switch1</div>
<div role="switch" aria-checked="true">Switch2</div>
<div role="switch" aria-checked="mixed">Switch3</div>
<div role="switch" aria-checked="false">Switch2</div>
<div role="switch" aria-checked="true">Switch3</div>
<!-- "mixed" is not a valid value for aria-pressed on switches. -->
<div role="switch" aria-checked="mixed">Switch4</div>
</body>
</html>
android.webkit.WebView focusable focused scrollable
++android.widget.Button role_description='button' clickable focusable name='Regular button'
++android.widget.ToggleButton role_description='toggle button' checkable clickable focusable name='Toggle button'
\ No newline at end of file
++android.widget.ToggleButton role_description='toggle button' checkable clickable focusable name='Toggle button'
++android.widget.ToggleButton role_description='toggle button' checkable checked clickable focusable name='Toggle button'
++android.widget.ToggleButton role_description='toggle button' checkable clickable focusable name='Toggle button'
rootWebArea
++button name='Regular button'
++toggleButton name='Toggle button' checkedState=false
\ No newline at end of file
++toggleButton name='Toggle button' checkedState=false
++toggleButton name='Toggle button' checkedState=true
++toggleButton name='Toggle button' checkedState=mixed
AXWebArea AXRoleDescription='HTML content'
++AXButton AXRoleDescription='button' AXTitle='Regular button'
++AXCheckBox AXSubrole=AXToggleButton AXRoleDescription='toggle button' AXTitle='Toggle button' AXValue='0'
++AXCheckBox AXSubrole=AXToggleButton AXRoleDescription='toggle button' AXTitle='Toggle button' AXValue='1'
++AXCheckBox AXSubrole=AXToggleButton AXRoleDescription='toggle button' AXTitle='Toggle button' AXValue='2'
ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE
++ROLE_SYSTEM_PUSHBUTTON FOCUSABLE
++IA2_ROLE_TOGGLE_BUTTON FOCUSABLE IA2_STATE_CHECKABLE checkable:true
\ No newline at end of file
++IA2_ROLE_TOGGLE_BUTTON FOCUSABLE IA2_STATE_CHECKABLE checkable:true
++IA2_ROLE_TOGGLE_BUTTON PRESSED FOCUSABLE IA2_STATE_CHECKABLE checkable:true
++IA2_ROLE_TOGGLE_BUTTON MIXED FOCUSABLE IA2_STATE_CHECKABLE checkable:true
<!--
@WIN-DENY:name*
@WIN-ALLOW:STATE_SYSTEM_*
@MAC-ALLOW:AXSubrole=*
@MAC-ALLOW:AXRoleDescription=*
-->
......@@ -7,5 +8,7 @@
<body>
<div tabindex=0 role="button">Regular button</div>
<div tabindex=0 role="button" aria-pressed="false">Toggle button</div>
<div tabindex=0 role="button" aria-pressed="true">Toggle button</div>
<div tabindex=0 role="button" aria-pressed="mixed">Toggle button</div>
</body>
</html>
......@@ -3574,10 +3574,8 @@ int32_t AXPlatformNodeWin::ComputeIA2State() {
const AXNodeData& data = GetData();
int32_t ia2_state = IA2_STATE_OPAQUE;
const auto checked_state = data.GetCheckedState();
if (checked_state != ax::mojom::CheckedState::kNone) {
if (HasIntAttribute(ax::mojom::IntAttribute::kCheckedState))
ia2_state |= IA2_STATE_CHECKABLE;
}
if (HasIntAttribute(ax::mojom::IntAttribute::kInvalidState) &&
GetIntAttribute(ax::mojom::IntAttribute::kInvalidState) !=
......@@ -3849,7 +3847,7 @@ std::vector<base::string16> AXPlatformNodeWin::ComputeIA2Attributes() {
IntAttributeToIA2(result, ax::mojom::IntAttribute::kPosInSet, "posinset");
if (HasIntAttribute(ax::mojom::IntAttribute::kCheckedState))
result.push_back(L"checkable:true");
result.emplace_back(L"checkable:true");
// Expose live region attributes.
StringAttributeToIA2(result, ax::mojom::StringAttribute::kLiveStatus, "live");
......@@ -4584,14 +4582,45 @@ base::string16 AXPlatformNodeWin::ComputeUIAProperties() {
"busy");
HtmlAttributeToUIAAriaProperty(properties, "aria-channel", "channel");
if (HasIntAttribute(ax::mojom::IntAttribute::kCheckedState)) {
base::string16 checked_property =
data.role == ax::mojom::Role::kToggleButton ? L"pressed" : L"checked";
bool is_checked = static_cast<ax::mojom::CheckedState>(GetIntAttribute(
ax::mojom::IntAttribute::kCheckedState)) ==
ax::mojom::CheckedState::kTrue;
properties.push_back(checked_property + L"=" +
(is_checked ? L"true" : L"false"));
switch (data.GetCheckedState()) {
case ax::mojom::CheckedState::kNone:
break;
case ax::mojom::CheckedState::kFalse:
if (data.role == ax::mojom::Role::kToggleButton) {
properties.emplace_back(L"pressed=false");
} else if (data.role == ax::mojom::Role::kSwitch) {
// ARIA switches are exposed to Windows accessibility as toggle buttons.
// For maximum compatibility with ATs, we expose both the pressed and
// checked states.
properties.emplace_back(L"pressed=false");
properties.emplace_back(L"checked=false");
} else {
properties.emplace_back(L"checked=false");
}
break;
case ax::mojom::CheckedState::kTrue:
if (data.role == ax::mojom::Role::kToggleButton) {
properties.emplace_back(L"pressed=true");
} else if (data.role == ax::mojom::Role::kSwitch) {
// ARIA switches are exposed to Windows accessibility as toggle buttons.
// For maximum compatibility with ATs, we expose both the pressed and
// checked states.
properties.emplace_back(L"pressed=true");
properties.emplace_back(L"checked=true");
} else {
properties.emplace_back(L"checked=true");
}
break;
case ax::mojom::CheckedState::kMixed:
if (data.role == ax::mojom::Role::kToggleButton) {
properties.emplace_back(L"pressed=mixed");
} else if (data.role == ax::mojom::Role::kSwitch) {
// This is disallowed both by the ARIA standard and by Blink.
NOTREACHED();
} else {
properties.emplace_back(L"checked=mixed");
}
break;
}
const auto restriction = static_cast<ax::mojom::Restriction>(
......@@ -5367,19 +5396,26 @@ int AXPlatformNodeWin::MSAAState() {
//
// Checked state
//
const auto checked_state = static_cast<ax::mojom::CheckedState>(
GetIntAttribute(ax::mojom::IntAttribute::kCheckedState));
switch (checked_state) {
switch (data.GetCheckedState()) {
case ax::mojom::CheckedState::kNone:
case ax::mojom::CheckedState::kFalse:
break;
case ax::mojom::CheckedState::kTrue:
msaa_state |= data.role == ax::mojom::Role::kToggleButton
? STATE_SYSTEM_PRESSED
: STATE_SYSTEM_CHECKED;
if (data.role == ax::mojom::Role::kToggleButton) {
msaa_state |= STATE_SYSTEM_PRESSED;
} else if (data.role == ax::mojom::Role::kSwitch) {
// ARIA switches are exposed to Windows accessibility as toggle buttons.
// For maximum compatibility with ATs, we expose both the pressed and
// checked states.
msaa_state |= STATE_SYSTEM_PRESSED | STATE_SYSTEM_CHECKED;
} else {
msaa_state |= STATE_SYSTEM_CHECKED;
}
break;
case ax::mojom::CheckedState::kMixed:
msaa_state |= STATE_SYSTEM_MIXED;
break;
default:
break;
}
const auto restriction = static_cast<ax::mojom::Restriction>(
......
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