Bug 1480058 part 3: Support accessible selection retrieval methods for XUL tabs with aria-multiselectable. r?surkov
The XULSelectControlAccessible selection methods don't handle ARIA selection.
Therefore, if aria-multiselectable is set, use the base implementation of the selection retrieval methods.
We don't bother overriding the selection setting methods because implementations (e.g. browser tabs) don't support setting of aria-selected by the a11y engine and we still want to be able to set the primary selected item according to XUL.
Being able to retrieve multiple selection programmatically is far more important than being able to set it.
MozReview-Commit-ID: CmVp9KyieMY
--- a/accessible/tests/mochitest/selectable/a11y.ini
+++ b/accessible/tests/mochitest/selectable/a11y.ini
@@ -3,9 +3,10 @@ support-files =
!/accessible/tests/mochitest/*.js
!/accessible/tests/mochitest/treeview.css
[test_aria.html]
[test_listbox.xul]
[test_menu.xul]
[test_menulist.xul]
[test_select.html]
+[test_tabs.xul]
[test_tree.xul]
new file mode 100644
--- /dev/null
+++ b/accessible/tests/mochitest/selectable/test_tabs.xul
@@ -0,0 +1,94 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
+ type="text/css"?>
+
+<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ title="XUL tabs selectable tests">
+
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
+
+ <script type="application/javascript"
+ src="../common.js" />
+ <script type="application/javascript"
+ src="../role.js" />
+ <script type="application/javascript"
+ src="../states.js" />
+ <script type="application/javascript"
+ src="../selectable.js" />
+
+ <script type="application/javascript">
+ <![CDATA[
+
+ ////////////////////////////////////////////////////////////////////////////
+ // Test
+
+ function doTest()
+ {
+ var id = "tabs_single";
+ ok(isAccessible(id, [nsIAccessibleSelectable]),
+ "No selectable accessible for tabs_single");
+ var select = getAccessible(id, [nsIAccessibleSelectable]);
+
+ testSelectableSelection(select, ["tab_single1"]);
+
+ select.unselectAll();
+ select.addItemToSelection(1); // tab_single2
+ testSelectableSelection(select, ["tab_single2"], "select tab_single2: ");
+
+ id = "tabs_multi";
+ ok(isAccessible(id, [nsIAccessibleSelectable]),
+ "No selectable accessible for tabs_multi");
+ select = getAccessible(id, [nsIAccessibleSelectable]);
+
+ // Make sure both XUL selection and ARIA selection are included.
+ testSelectableSelection(select, ["tab_multi_xul1", "tab_multi_aria"]);
+
+ select.unselectAll();
+ select.addItemToSelection(2); // tab_multi_xul2
+ // We can only affect XUL selection, so ARIA selection won't change.
+ testSelectableSelection(select, ["tab_multi_aria", "tab_multi_xul2"],
+ "select tab_multi_xul2: ");
+
+ SimpleTest.finish();
+ }
+
+ SimpleTest.waitForExplicitFinish();
+ addA11yLoadEvent(doTest);
+ ]]>
+ </script>
+
+ <hbox flex="1" style="overflow: auto;">
+ <body xmlns="http://www.w3.org/1999/xhtml">
+ <a target="_blank"
+ href="https://bugzilla.mozilla.org/show_bug.cgi?id=1480058"
+ title="XUL tabs don't support ARIA selection">
+ Mozilla Bug 1480058
+ </a><br/>
+ <p id="display"></p>
+ <div id="content" style="display: none">
+ </div>
+ <pre id="test">
+ </pre>
+ </body>
+
+ <vbox flex="1">
+ <tabbox>
+ <tabs id="tabs_single">
+ <tab id="tab_single1" label="tab1" selected="true"/>
+ <tab id="tab_single2" label="tab2"/>
+ </tabs>
+ </tabbox>
+
+ <tabbox>
+ <tabs id="tabs_multi" aria-multiselectable="true">
+ <tab id="tab_multi_xul1" label="tab1" selected="true"/>
+ <tab id="tab_multi_aria" label="tab2" aria-selected="true"/>
+ <tab id="tab_multi_xul2" label="tab3"/>
+ </tabs>
+ </tabbox>
+ </vbox>
+ </hbox>
+
+</window>
--- a/accessible/xul/XULTabAccessible.cpp
+++ b/accessible/xul/XULTabAccessible.cpp
@@ -176,16 +176,66 @@ XULTabsAccessible::ApplyARIAState(uint64
{
XULSelectControlAccessible::ApplyARIAState(aState);
// XUL tabs has an implicit ARIA role of tablist, so support
// aria-multiselectable.
MOZ_ASSERT(Elm());
aria::MapToState(aria::eARIAMultiSelectable, Elm(), aState);
}
+// XUL tabs is a single selection control and doesn't allow ARIA selection.
+// However, if aria-multiselectable is used, it becomes a multiselectable
+// control, where both native and ARIA markup are used to set selection.
+// Therefore, if aria-multiselectable is set, use the base implementation of
+// the selection retrieval methods in order to support ARIA selection.
+// We don't bother overriding the selection setting methods because
+// current front-end code using XUL tabs doesn't support setting of
+// aria-selected by the a11y engine and we still want to be able to set the
+// primary selected item according to XUL.
+
+void
+XULTabsAccessible::SelectedItems(nsTArray<Accessible*>* aItems)
+{
+ if (nsAccUtils::IsARIAMultiSelectable(this)) {
+ AccessibleWrap::SelectedItems(aItems);
+ } else {
+ XULSelectControlAccessible::SelectedItems(aItems);
+ }
+}
+
+Accessible*
+XULTabsAccessible::GetSelectedItem(uint32_t aIndex)
+{
+ if (nsAccUtils::IsARIAMultiSelectable(this)) {
+ return AccessibleWrap::GetSelectedItem(aIndex);
+ }
+
+ return XULSelectControlAccessible::GetSelectedItem(aIndex);
+}
+
+uint32_t
+XULTabsAccessible::SelectedItemCount()
+{
+ if (nsAccUtils::IsARIAMultiSelectable(this)) {
+ return AccessibleWrap::SelectedItemCount();
+ }
+
+ return XULSelectControlAccessible::SelectedItemCount();
+}
+
+bool
+XULTabsAccessible::IsItemSelected(uint32_t aIndex)
+{
+ if (nsAccUtils::IsARIAMultiSelectable(this)) {
+ return AccessibleWrap::IsItemSelected(aIndex);
+ }
+
+ return XULSelectControlAccessible::IsItemSelected(aIndex);
+}
+
////////////////////////////////////////////////////////////////////////////////
// XULTabpanelsAccessible
////////////////////////////////////////////////////////////////////////////////
role
XULTabpanelsAccessible::NativeRole() const
{
--- a/accessible/xul/XULTabAccessible.h
+++ b/accessible/xul/XULTabAccessible.h
@@ -49,16 +49,22 @@ public:
// Accessible
virtual void Value(nsString& aValue) const override;
virtual a11y::role NativeRole() const override;
virtual void ApplyARIAState(uint64_t* aState) const override;
// ActionAccessible
virtual uint8_t ActionCount() const override;
+ // SelectAccessible
+ virtual void SelectedItems(nsTArray<Accessible*>* aItems) override;
+ virtual uint32_t SelectedItemCount() override;
+ virtual Accessible* GetSelectedItem(uint32_t aIndex) override;
+ virtual bool IsItemSelected(uint32_t aIndex) override;
+
protected:
// Accessible
virtual ENameValueFlag NativeName(nsString& aName) const override;
};
/**
* A container of tab panels, xul:tabpanels element.