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"
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 : HyperTextAccessibleWrap(aContent
, aDoc
) {}
31 ////////////////////////////////////////////////////////////////////////////////
32 // XULTabAccessible: LocalAccessible
34 uint8_t XULTabAccessible::ActionCount() const { return 1; }
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()->AttrValueIs(kNameSpaceID_None
, nsGkAtoms::pinned
,
73 nsGkAtoms::_true
, eCaseMatters
)) {
74 state
|= states::PINNED
;
81 uint64_t XULTabAccessible::NativeInteractiveState() const {
82 uint64_t state
= LocalAccessible::NativeInteractiveState();
83 return (state
& states::UNAVAILABLE
) ? state
: state
| states::SELECTABLE
;
86 Relation
XULTabAccessible::RelationByType(RelationType aType
) const {
87 Relation rel
= AccessibleWrap::RelationByType(aType
);
88 if (aType
!= RelationType::LABEL_FOR
) return rel
;
90 // Expose 'LABEL_FOR' relation on tab accessible for tabpanel accessible.
92 nsIContent
* parent
= mContent
->AsElement()->Closest("tabs"_ns
, rv
);
93 if (!parent
) return rel
;
95 nsCOMPtr
<nsIDOMXULRelatedElement
> tabsElm
=
96 parent
->AsElement()->AsXULRelated();
97 if (!tabsElm
) return rel
;
99 RefPtr
<mozilla::dom::Element
> tabpanelElement
;
100 tabsElm
->GetRelatedElement(GetNode(), getter_AddRefs(tabpanelElement
));
101 if (!tabpanelElement
) return rel
;
103 rel
.AppendTarget(mDoc
, tabpanelElement
);
107 void XULTabAccessible::ApplyARIAState(uint64_t* aState
) const {
108 HyperTextAccessibleWrap::ApplyARIAState(aState
);
109 // XUL tab has an implicit ARIA role of tab, so support aria-selected.
110 // Don't use aria::MapToState because that will set the SELECTABLE state
111 // even if the tab is disabled.
112 if (nsAccUtils::IsARIASelected(this)) {
113 *aState
|= states::SELECTED
;
117 ////////////////////////////////////////////////////////////////////////////////
119 ////////////////////////////////////////////////////////////////////////////////
121 XULTabsAccessible::XULTabsAccessible(nsIContent
* aContent
, DocAccessible
* aDoc
)
122 : XULSelectControlAccessible(aContent
, aDoc
) {}
124 role
XULTabsAccessible::NativeRole() const { return roles::PAGETABLIST
; }
126 uint8_t XULTabsAccessible::ActionCount() const { return 0; }
128 void XULTabsAccessible::Value(nsString
& aValue
) const { aValue
.Truncate(); }
130 ENameValueFlag
XULTabsAccessible::NativeName(nsString
& aName
) const {
135 void XULTabsAccessible::ApplyARIAState(uint64_t* aState
) const {
136 XULSelectControlAccessible::ApplyARIAState(aState
);
137 // XUL tabs has an implicit ARIA role of tablist, so support
138 // aria-multiselectable.
140 aria::MapToState(aria::eARIAMultiSelectable
, Elm(), aState
);
143 // XUL tabs is a single selection control and doesn't allow ARIA selection.
144 // However, if aria-multiselectable is used, it becomes a multiselectable
145 // control, where both native and ARIA markup are used to set selection.
146 // Therefore, if aria-multiselectable is set, use the base implementation of
147 // the selection retrieval methods in order to support ARIA selection.
148 // We don't bother overriding the selection setting methods because
149 // current front-end code using XUL tabs doesn't support setting of
150 // aria-selected by the a11y engine and we still want to be able to set the
151 // primary selected item according to XUL.
153 void XULTabsAccessible::SelectedItems(nsTArray
<LocalAccessible
*>* aItems
) {
154 if (nsAccUtils::IsARIAMultiSelectable(this)) {
155 AccessibleWrap::SelectedItems(aItems
);
157 XULSelectControlAccessible::SelectedItems(aItems
);
161 LocalAccessible
* XULTabsAccessible::GetSelectedItem(uint32_t aIndex
) {
162 if (nsAccUtils::IsARIAMultiSelectable(this)) {
163 return AccessibleWrap::GetSelectedItem(aIndex
);
166 return XULSelectControlAccessible::GetSelectedItem(aIndex
);
169 uint32_t XULTabsAccessible::SelectedItemCount() {
170 if (nsAccUtils::IsARIAMultiSelectable(this)) {
171 return AccessibleWrap::SelectedItemCount();
174 return XULSelectControlAccessible::SelectedItemCount();
177 bool XULTabsAccessible::IsItemSelected(uint32_t aIndex
) {
178 if (nsAccUtils::IsARIAMultiSelectable(this)) {
179 return AccessibleWrap::IsItemSelected(aIndex
);
182 return XULSelectControlAccessible::IsItemSelected(aIndex
);
185 ////////////////////////////////////////////////////////////////////////////////
186 // XULTabpanelsAccessible
187 ////////////////////////////////////////////////////////////////////////////////
189 role
XULTabpanelsAccessible::NativeRole() const { return roles::PANE
; }
191 ////////////////////////////////////////////////////////////////////////////////
192 // XULTabpanelAccessible
193 ////////////////////////////////////////////////////////////////////////////////
195 XULTabpanelAccessible::XULTabpanelAccessible(nsIContent
* aContent
,
197 : AccessibleWrap(aContent
, aDoc
) {}
199 role
XULTabpanelAccessible::NativeRole() const { return roles::PROPERTYPAGE
; }
201 Relation
XULTabpanelAccessible::RelationByType(RelationType aType
) const {
202 Relation rel
= AccessibleWrap::RelationByType(aType
);
203 if (aType
!= RelationType::LABELLED_BY
) return rel
;
205 // Expose 'LABELLED_BY' relation on tabpanel accessible for tab accessible.
206 if (!mContent
->GetParent()) return rel
;
208 nsCOMPtr
<nsIDOMXULRelatedElement
> tabpanelsElm
=
209 mContent
->GetParent()->AsElement()->AsXULRelated();
210 if (!tabpanelsElm
) return rel
;
212 RefPtr
<mozilla::dom::Element
> tabElement
;
213 tabpanelsElm
->GetRelatedElement(GetNode(), getter_AddRefs(tabElement
));
214 if (!tabElement
) return rel
;
216 rel
.AppendTarget(mDoc
, tabElement
);