ARIA 1.2 non-editable combobox
- Expose value, but not name, based on descendant text
- Expose correct role on Mac (popup button)
Bug: 1069150
Change-Id: I16119966a1e6c8a1eee88ef61c7268c5d3384341
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2142611
Commit-Queue: Aaron Leventhal <aleventhal@chromium.org>
Reviewed-by: Dominic Mazzoni <dmazzoni@chromium.org>
Cr-Commit-Position: refs/heads/master@{#758007}
This commit is contained in:

committed by
Commit Bot

parent
ff7b2235b0
commit
b5ac2bd6b7
content
browser
test
data
accessibility
aria
aria-combobox-uneditable-expected-android.txtaria-combobox-uneditable-expected-auralinux.txtaria-combobox-uneditable-expected-blink.txtaria-combobox-uneditable-expected-mac.txtaria-combobox-uneditable-expected-uia-win.txtaria-combobox-uneditable-expected-win.txtaria-combobox-uneditable.htmlaria-haspopup-expected-mac.txtlabel-with-selected-option-expected-blink.txt
event
third_party/blink/renderer/modules/accessibility
ui/accessibility/platform
@ -268,6 +268,11 @@ IN_PROC_BROWSER_TEST_P(DumpAccessibilityEventsTest,
|
||||
RunEventTest(FILE_PATH_LITERAL("aria-controls-changed.html"));
|
||||
}
|
||||
|
||||
IN_PROC_BROWSER_TEST_P(DumpAccessibilityEventsTest,
|
||||
AccessibilityEventsAriaComboBoxUneditable) {
|
||||
RunEventTest(FILE_PATH_LITERAL("aria-combo-box-uneditable.html"));
|
||||
}
|
||||
|
||||
#if defined(OS_WIN)
|
||||
#define MAYBE_AccessibilityEventsAriaDisabledChanged \
|
||||
DISABLED_AccessibilityEventsAriaDisabledChanged
|
||||
|
@ -569,6 +569,11 @@ IN_PROC_BROWSER_TEST_P(DumpAccessibilityTreeTest,
|
||||
RunAriaTest(FILE_PATH_LITERAL("aria-combobox.html"));
|
||||
}
|
||||
|
||||
IN_PROC_BROWSER_TEST_P(DumpAccessibilityTreeTest,
|
||||
AccessibilityAriaComboboxUneditable) {
|
||||
RunAriaTest(FILE_PATH_LITERAL("aria-combobox-uneditable.html"));
|
||||
}
|
||||
|
||||
#if defined(OS_ANDROID)
|
||||
// TODO(crbug.com/986673): test is flaky on android.
|
||||
#define MAYBE_AccessibilityAriaOnePointOneCombobox \
|
||||
|
@ -0,0 +1,7 @@
|
||||
android.webkit.WebView focusable focused scrollable
|
||||
++android.view.View name='Choose a fruit, with text content'
|
||||
++android.widget.Spinner clickable focusable name='Choose a fruit, with text content'
|
||||
++android.widget.ListView role_description='list box' clickable collection item_count=3 row_count=3
|
||||
++++android.view.View clickable collection_item focusable selected name='Apple'
|
||||
++++android.view.View clickable collection_item focusable name='Banana' item_index=1 row_index=1
|
||||
++++android.view.View clickable collection_item focusable name='Cherry' item_index=2 row_index=2
|
@ -0,0 +1,9 @@
|
||||
[document web]
|
||||
++[section] label-for
|
||||
++++[static] name='Choose a fruit, with text content'
|
||||
++[combo box] name='Choose a fruit, with text content' expandable controller-for labelled-by haspopup:listbox valuetext:Apple
|
||||
++++[static] name='Apple'
|
||||
++[list box] controlled-by
|
||||
++++[list item] name='Apple' selectable selected
|
||||
++++[list item] name='Banana' selectable
|
||||
++++[list item] name='Cherry' selectable
|
@ -0,0 +1,13 @@
|
||||
rootWebArea
|
||||
++genericContainer ignored
|
||||
++++genericContainer ignored
|
||||
++++++genericContainer
|
||||
++++++++staticText name='Choose a fruit, with text content'
|
||||
++++++++++inlineTextBox name='Choose a fruit, with text content'
|
||||
++++++comboBoxMenuButton collapsed name='Choose a fruit, with text content' value='Apple' haspopup=listbox controlsIds=listBox
|
||||
++++++++staticText name='Apple'
|
||||
++++++++++inlineTextBox name='Apple'
|
||||
++++++listBox
|
||||
++++++++listBoxOption name='Apple' selected=true
|
||||
++++++++listBoxOption name='Banana' selected=false
|
||||
++++++++listBoxOption name='Cherry' selected=false
|
@ -0,0 +1,9 @@
|
||||
AXWebArea AXFocused='1'
|
||||
++AXGroup
|
||||
++++AXStaticText AXValue='Choose a fruit, with text content'
|
||||
++AXPopUpButton AXTitle='Choose a fruit, with text content' AXValue='Apple' AXLinkedUIElements=["AXList"]
|
||||
++++AXStaticText AXValue='Apple'
|
||||
++AXList
|
||||
++++AXStaticText AXValue='Apple'
|
||||
++++AXStaticText AXValue='Banana'
|
||||
++++AXStaticText AXValue='Cherry'
|
@ -0,0 +1,9 @@
|
||||
Document
|
||||
++Group IsControlElement=false
|
||||
++++Text Name='Choose a fruit, with text content'
|
||||
++ComboBox Name='Choose a fruit, with text content' ExpandCollapse.ExpandCollapseState='Collapsed' Selection.CanSelectMultiple=false Selection.IsSelectionRequired=false Value.Value='Apple'
|
||||
++++Text Name='Apple'
|
||||
++List Selection.CanSelectMultiple=false Selection.IsSelectionRequired=false
|
||||
++++ListItem Name='Apple' SelectionItem.IsSelected=true
|
||||
++++ListItem Name='Banana' SelectionItem.IsSelected=false
|
||||
++++ListItem Name='Cherry' SelectionItem.IsSelected=false
|
@ -0,0 +1,9 @@
|
||||
ROLE_SYSTEM_DOCUMENT FOCUSED READONLY FOCUSABLE ia2_hypertext='<obj0><obj1><obj2>'
|
||||
++IA2_ROLE_SECTION ia2_hypertext='Choose a fruit, with text content'
|
||||
++++ROLE_SYSTEM_STATICTEXT name='Choose a fruit, with text content' ia2_hypertext='Choose a fruit, with text content'
|
||||
++ROLE_SYSTEM_COMBOBOX name='Choose a fruit, with text content' value='Apple' COLLAPSED FOCUSABLE HASPOPUP haspopup:listbox ia2_hypertext='Apple'
|
||||
++++ROLE_SYSTEM_STATICTEXT name='Apple' ia2_hypertext='Apple'
|
||||
++ROLE_SYSTEM_LIST ia2_hypertext='<obj0><obj1><obj2>'
|
||||
++++ROLE_SYSTEM_LISTITEM name='Apple' SELECTED FOCUSED FOCUSABLE SELECTABLE ia2_hypertext='Apple'
|
||||
++++ROLE_SYSTEM_LISTITEM name='Banana' FOCUSABLE SELECTABLE ia2_hypertext='Banana'
|
||||
++++ROLE_SYSTEM_LISTITEM name='Cherry' FOCUSABLE SELECTABLE ia2_hypertext='Cherry'
|
@ -0,0 +1,27 @@
|
||||
<!DOCTYPE html>
|
||||
<!--
|
||||
@MAC-ALLOW:AXFocused='1'
|
||||
@MAC-ALLOW:AXLinkedUIElements*
|
||||
@MAC-DENY:AXLinkedUIElements=[]
|
||||
@MAC-ALLOW:AXTitleUIElement*
|
||||
@WIN-DENY:description*
|
||||
@WIN-ALLOW:FOCUS*
|
||||
@WIN-ALLOW:haspopup*
|
||||
@WIN-ALLOW:ia2_hypertext=*
|
||||
@WIN-ALLOW:SELECT*
|
||||
@AURALINUX-ALLOW:collapsed*
|
||||
@AURALINUX-ALLOW:expand*
|
||||
@AURALINUX-ALLOW:haspopup:*
|
||||
@AURALINUX-ALLOW:select*
|
||||
@AURALINUX-ALLOW:value*
|
||||
@BLINK-ALLOW:haspopup*
|
||||
-->
|
||||
<!-- Test a combobox box that acts like a <select size=1>. The value is computed like a name from descendants.
|
||||
Note that some platforms do not call this a combobox, e.g. Mac calls this a popup button -->
|
||||
<div id="combo1-label">Choose a fruit, with text content</div>
|
||||
<div aria-controls="listbox1" aria-expanded="false" aria-haspopup="listbox" aria-labelledby="combo1-label" role="combobox" tabindex="0">Apple</div>
|
||||
<div role="listbox" id="listbox1">
|
||||
<div role="option" id="combo1-0" aria-selected="true">Apple</div>
|
||||
<div role="option" id="combo1-1">Banana</div>
|
||||
<div role="option" id="combo1-2">Cherry</div>
|
||||
</div>
|
@ -1,10 +1,10 @@
|
||||
AXWebArea
|
||||
++AXButton AXHasPopup='1' AXHasPopupValue='menu'
|
||||
++AXButton
|
||||
++AXButton AXHasPopup='1' AXHasPopupValue='menu'
|
||||
++AXButton AXHasPopup='1' AXHasPopupValue='listbox'
|
||||
++AXButton AXHasPopup='1' AXHasPopupValue='grid'
|
||||
++AXButton AXHasPopup='1' AXHasPopupValue='dialog'
|
||||
++AXButton AXHasPopup='1' AXHasPopupValue='menu'
|
||||
++AXButton AXHasPopup='1' AXHasPopupValue='listbox'
|
||||
++AXButton AXHasPopup='1' AXHasPopupValue='listbox'
|
||||
++AXPopUpButton AXHasPopup='1' AXHasPopupValue='menu'
|
||||
++AXPopUpButton
|
||||
++AXPopUpButton AXHasPopup='1' AXHasPopupValue='menu'
|
||||
++AXPopUpButton AXHasPopup='1' AXHasPopupValue='listbox'
|
||||
++AXPopUpButton AXHasPopup='1' AXHasPopupValue='grid'
|
||||
++AXPopUpButton AXHasPopup='1' AXHasPopupValue='dialog'
|
||||
++AXPopUpButton AXHasPopup='1' AXHasPopupValue='menu'
|
||||
++AXPopUpButton AXHasPopup='1' AXHasPopupValue='listbox'
|
||||
++AXPopUpButton AXHasPopup='1' AXHasPopupValue='listbox'
|
@ -31,7 +31,7 @@ rootWebArea
|
||||
++++++++++++listBoxOption ignored name='3' selected=false
|
||||
++++++genericContainer ignored
|
||||
++++++++checkBox name='Test 5: Flash the screen two times.' checkedState=false
|
||||
++++++++comboBoxMenuButton name='two'
|
||||
++++++++comboBoxMenuButton value='two'
|
||||
++++++++++listBox ignored
|
||||
++++++++++++listBoxOption ignored name='1' selected=false
|
||||
++++++++++++listBoxOption ignored name='two' selected=true
|
||||
|
@ -0,0 +1 @@
|
||||
AXValueChanged on AXPopUpButton AXValue="Orange"
|
@ -0,0 +1 @@
|
||||
EVENT_OBJECT_VALUECHANGE on <div> role=ROLE_SYSTEM_COMBOBOX value="Orange" COLLAPSED,FOCUSABLE,HASPOPUP
|
@ -0,0 +1,12 @@
|
||||
<!--
|
||||
@WIN-DENY:*
|
||||
@WIN-ALLOW:EVENT_OBJECT_VALUECHANGE*
|
||||
-->
|
||||
<div aria-controls="listbox1" aria-expanded="false" aria-haspopup="listbox" role="combobox" tabindex="0">Apple</div>
|
||||
<div role="listbox" id="listbox1"><!-- Options would normally go here --></div>
|
||||
<script>
|
||||
function go() {
|
||||
var combo_box = document.querySelector('[role=combobox]');
|
||||
combo_box.innerText = 'Orange';
|
||||
}
|
||||
</script>
|
@ -1533,6 +1533,12 @@ String AXLayoutObject::StringValue() const {
|
||||
}
|
||||
}
|
||||
|
||||
// ARIA combobox can get value from inner contents.
|
||||
if (AriaRoleAttribute() == ax::mojom::Role::kComboBoxMenuButton) {
|
||||
AXObjectSet visited;
|
||||
return TextFromDescendants(visited, false);
|
||||
}
|
||||
|
||||
// FIXME: We might need to implement a value here for more types
|
||||
// FIXME: It would be better not to advertise a value at all for the types for
|
||||
// which we don't implement one; this would require subclassing or making
|
||||
|
@ -2157,6 +2157,12 @@ String AXNodeObject::StringValue() const {
|
||||
}
|
||||
}
|
||||
|
||||
// ARIA combobox can get value from inner contents.
|
||||
if (AriaRoleAttribute() == ax::mojom::Role::kComboBoxMenuButton) {
|
||||
AXObjectSet visited;
|
||||
return TextFromDescendants(visited, false);
|
||||
}
|
||||
|
||||
return String();
|
||||
}
|
||||
|
||||
|
@ -159,6 +159,8 @@ class MODULES_EXPORT AXNodeObject : public AXObject {
|
||||
KURL Url() const override;
|
||||
AXObject* ChooserPopup() const override;
|
||||
String StringValue() const override;
|
||||
String TextFromDescendants(AXObjectSet& visited,
|
||||
bool recursive) const override;
|
||||
|
||||
// ARIA attributes.
|
||||
ax::mojom::Role AriaRoleAttribute() const final;
|
||||
@ -251,8 +253,6 @@ class MODULES_EXPORT AXNodeObject : public AXObject {
|
||||
Member<Node> node_;
|
||||
|
||||
bool IsNativeCheckboxInMixedState() const;
|
||||
String TextFromDescendants(AXObjectSet& visited,
|
||||
bool recursive) const override;
|
||||
String NativeTextAlternative(AXObjectSet& visited,
|
||||
ax::mojom::NameFrom&,
|
||||
AXRelatedObjectVector*,
|
||||
|
@ -3587,7 +3587,6 @@ bool AXObject::NameFromContents(bool recursive) const {
|
||||
case ax::mojom::Role::kCell:
|
||||
case ax::mojom::Role::kCheckBox:
|
||||
case ax::mojom::Role::kColumnHeader:
|
||||
case ax::mojom::Role::kComboBoxMenuButton:
|
||||
case ax::mojom::Role::kDocBackLink:
|
||||
case ax::mojom::Role::kDocBiblioRef:
|
||||
case ax::mojom::Role::kDocNoteRef:
|
||||
@ -3598,7 +3597,6 @@ bool AXObject::NameFromContents(bool recursive) const {
|
||||
case ax::mojom::Role::kLineBreak:
|
||||
case ax::mojom::Role::kLink:
|
||||
case ax::mojom::Role::kListBoxOption:
|
||||
case ax::mojom::Role::kMenuButton:
|
||||
case ax::mojom::Role::kMenuItem:
|
||||
case ax::mojom::Role::kMenuItemCheckBox:
|
||||
case ax::mojom::Role::kMenuItemRadio:
|
||||
@ -3630,6 +3628,7 @@ bool AXObject::NameFromContents(bool recursive) const {
|
||||
case ax::mojom::Role::kClient:
|
||||
case ax::mojom::Role::kColorWell:
|
||||
case ax::mojom::Role::kColumn:
|
||||
case ax::mojom::Role::kComboBoxMenuButton: // Only value from content.
|
||||
case ax::mojom::Role::kComboBoxGrouping:
|
||||
case ax::mojom::Role::kComment:
|
||||
case ax::mojom::Role::kComplementary:
|
||||
@ -3699,6 +3698,7 @@ bool AXObject::NameFromContents(bool recursive) const {
|
||||
case ax::mojom::Role::kMenuListPopup:
|
||||
case ax::mojom::Role::kMenu:
|
||||
case ax::mojom::Role::kMenuBar:
|
||||
case ax::mojom::Role::kMenuButton: // Only value from content, not name.
|
||||
case ax::mojom::Role::kMeter:
|
||||
case ax::mojom::Role::kNavigation:
|
||||
case ax::mojom::Role::kNote:
|
||||
|
@ -1158,7 +1158,8 @@ void AXPlatformNodeBase::ComputeAttributes(PlatformAttributeList* attributes) {
|
||||
}
|
||||
|
||||
// Expose slider value.
|
||||
if (GetData().IsRangeValueSupported()) {
|
||||
if (GetData().IsRangeValueSupported() ||
|
||||
GetData().role == ax::mojom::Role::kComboBoxMenuButton) {
|
||||
std::string value = base::UTF16ToUTF8(GetRangeValueText());
|
||||
if (!value.empty())
|
||||
AddAttributeToList("valuetext", value, attributes);
|
||||
|
@ -56,7 +56,7 @@ RoleMap BuildRoleMap() {
|
||||
{ax::mojom::Role::kColumn, NSAccessibilityColumnRole},
|
||||
{ax::mojom::Role::kColumnHeader, @"AXCell"},
|
||||
{ax::mojom::Role::kComboBoxGrouping, NSAccessibilityGroupRole},
|
||||
{ax::mojom::Role::kComboBoxMenuButton, NSAccessibilityButtonRole},
|
||||
{ax::mojom::Role::kComboBoxMenuButton, NSAccessibilityPopUpButtonRole},
|
||||
{ax::mojom::Role::kComment, NSAccessibilityGroupRole},
|
||||
{ax::mojom::Role::kComplementary, NSAccessibilityGroupRole},
|
||||
{ax::mojom::Role::kContentDeletion, NSAccessibilityGroupRole},
|
||||
|
Reference in New Issue
Block a user