1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "XULTabAccessible.h"
9 #include "nsAccUtils.h"
11 #include "mozilla/a11y/Role.h"
14 // NOTE: alphabetically ordered
15 #include "mozilla/dom/Document.h"
16 #include "nsIDOMXULSelectCntrlItemEl.h"
17 #include "nsIDOMXULRelatedElement.h"
18 #include "nsXULElement.h"
20 #include "mozilla/dom/BindingDeclarations.h"
22 using namespace mozilla::a11y
;
24 ////////////////////////////////////////////////////////////////////////////////
26 ////////////////////////////////////////////////////////////////////////////////
28 XULTabAccessible::XULTabAccessible(nsIContent
* aContent
, DocAccessible
* aDoc
)
29 : HyperTextAccessible(aContent
, aDoc
) {}
31 ////////////////////////////////////////////////////////////////////////////////
32 // XULTabAccessible: LocalAccessible
34 bool XULTabAccessible::HasPrimaryAction() const { return true; }
36 void XULTabAccessible::ActionNameAt(uint8_t aIndex
, nsAString
& aName
) {
37 if (aIndex
== eAction_Switch
) aName
.AssignLiteral("switch");
40 bool XULTabAccessible::DoAction(uint8_t index
) const {
41 if (index
== eAction_Switch
) {
42 // XXXbz Could this just FromContent?
43 RefPtr
<nsXULElement
> tab
= nsXULElement::FromNodeOrNull(mContent
);
45 tab
->Click(mozilla::dom::CallerType::System
);
52 ////////////////////////////////////////////////////////////////////////////////
53 // XULTabAccessible: LocalAccessible
55 role
XULTabAccessible::NativeRole() const { return roles::PAGETAB
; }
57 uint64_t XULTabAccessible::NativeState() const {
58 // Possible states: focused, focusable, unavailable(disabled), offscreen.
60 // get focus and disable status from base class
61 uint64_t state
= AccessibleWrap::NativeState();
63 // Check whether the tab is selected and/or pinned
64 nsCOMPtr
<nsIDOMXULSelectControlItemElement
> tab
=
65 Elm()->AsXULSelectControlItem();
67 bool selected
= false;
68 if (NS_SUCCEEDED(tab
->GetSelected(&selected
)) && selected
) {
69 state
|= states::SELECTED
;
72 if (mContent
->AsElement()->HasAttr(kNameSpaceID_None
, nsGkAtoms::pinned
)) {
73 state
|= states::PINNED
;
80 uint64_t XULTabAccessible::NativeInteractiveState() const {
81 uint64_t state
= LocalAccessible::NativeInteractiveState();
82 return (state
& states::UNAVAILABLE
) ? state
: state
| states::SELECTABLE
;
85 Relation
XULTabAccessible::RelationByType(RelationType aType
) const {
86 Relation rel
= AccessibleWrap::RelationByType(aType
);
87 if (aType
!= RelationType::LABEL_FOR
) return rel
;
89 // Expose 'LABEL_FOR' relation on tab accessible for tabpanel accessible.
91 nsIContent
* parent
= mContent
->AsElement()->Closest("tabs"_ns
, rv
);
92 if (!parent
) return rel
;
94 nsCOMPtr
<nsIDOMXULRelatedElement
> tabsElm
=
95 parent
->AsElement()->AsXULRelated();
96 if (!tabsElm
) return rel
;
98 RefPtr
<mozilla::dom::Element
> tabpanelElement
;
99 tabsElm
->GetRelatedElement(GetNode(), getter_AddRefs(tabpanelElement
));
100 if (!tabpanelElement
) return rel
;
102 rel
.AppendTarget(mDoc
, tabpanelElement
);
106 void XULTabAccessible::ApplyARIAState(uint64_t* aState
) const {
107 HyperTextAccessible::ApplyARIAState(aState
);
108 // XUL tab has an implicit ARIA role of tab, so support aria-selected.
109 // Don't use aria::MapToState because that will set the SELECTABLE state
110 // even if the tab is disabled.
111 if (nsAccUtils::IsARIASelected(this)) {
112 *aState
|= states::SELECTED
;
116 ////////////////////////////////////////////////////////////////////////////////
118 ////////////////////////////////////////////////////////////////////////////////
120 XULTabsAccessible::XULTabsAccessible(nsIContent
* aContent
, DocAccessible
* aDoc
)
121 : XULSelectControlAccessible(aContent
, aDoc
) {}
123 role
XULTabsAccessible::NativeRole() const { return roles::PAGETABLIST
; }
125 bool XULTabsAccessible::HasPrimaryAction() const { return false; }
127 void XULTabsAccessible::Value(nsString
& aValue
) const { aValue
.Truncate(); }
129 ENameValueFlag
XULTabsAccessible::NativeName(nsString
& aName
) const {
134 void XULTabsAccessible::ApplyARIAState(uint64_t* aState
) const {
135 XULSelectControlAccessible::ApplyARIAState(aState
);
136 // XUL tabs has an implicit ARIA role of tablist, so support
137 // aria-multiselectable.
139 aria::MapToState(aria::eARIAMultiSelectable
, Elm(), aState
);
142 // XUL tabs is a single selection control and doesn't allow ARIA selection.
143 // However, if aria-multiselectable is used, it becomes a multiselectable
144 // control, where both native and ARIA markup are used to set selection.
145 // Therefore, if aria-multiselectable is set, use the base implementation of
146 // the selection retrieval methods in order to support ARIA selection.
147 // We don't bother overriding the selection setting methods because
148 // current front-end code using XUL tabs doesn't support setting of
149 // aria-selected by the a11y engine and we still want to be able to set the
150 // primary selected item according to XUL.
152 void XULTabsAccessible::SelectedItems(nsTArray
<Accessible
*>* aItems
) {
153 if (nsAccUtils::IsARIAMultiSelectable(this)) {
154 AccessibleWrap::SelectedItems(aItems
);
156 XULSelectControlAccessible::SelectedItems(aItems
);
160 Accessible
* XULTabsAccessible::GetSelectedItem(uint32_t aIndex
) {
161 if (nsAccUtils::IsARIAMultiSelectable(this)) {
162 return AccessibleWrap::GetSelectedItem(aIndex
);
165 return XULSelectControlAccessible::GetSelectedItem(aIndex
);
168 uint32_t XULTabsAccessible::SelectedItemCount() {
169 if (nsAccUtils::IsARIAMultiSelectable(this)) {
170 return AccessibleWrap::SelectedItemCount();
173 return XULSelectControlAccessible::SelectedItemCount();
176 bool XULTabsAccessible::IsItemSelected(uint32_t aIndex
) {
177 if (nsAccUtils::IsARIAMultiSelectable(this)) {
178 return AccessibleWrap::IsItemSelected(aIndex
);
181 return XULSelectControlAccessible::IsItemSelected(aIndex
);
184 ////////////////////////////////////////////////////////////////////////////////
185 // XULTabpanelsAccessible
186 ////////////////////////////////////////////////////////////////////////////////
188 role
XULTabpanelsAccessible::NativeRole() const { return roles::PANE
; }
190 ////////////////////////////////////////////////////////////////////////////////
191 // XULTabpanelAccessible
192 ////////////////////////////////////////////////////////////////////////////////
194 XULTabpanelAccessible::XULTabpanelAccessible(nsIContent
* aContent
,
196 : AccessibleWrap(aContent
, aDoc
) {}
198 role
XULTabpanelAccessible::NativeRole() const { return roles::PROPERTYPAGE
; }
200 Relation
XULTabpanelAccessible::RelationByType(RelationType aType
) const {
201 Relation rel
= AccessibleWrap::RelationByType(aType
);
202 if (aType
!= RelationType::LABELLED_BY
) return rel
;
204 // Expose 'LABELLED_BY' relation on tabpanel accessible for tab accessible.
205 if (!mContent
->GetParent()) return rel
;
207 nsCOMPtr
<nsIDOMXULRelatedElement
> tabpanelsElm
=
208 mContent
->GetParent()->AsElement()->AsXULRelated();
209 if (!tabpanelsElm
) return rel
;
211 RefPtr
<mozilla::dom::Element
> tabElement
;
212 tabpanelsElm
->GetRelatedElement(GetNode(), getter_AddRefs(tabElement
));
213 if (!tabElement
) return rel
;
215 rel
.AppendTarget(mDoc
, tabElement
);