Backed out changeset 3152110c63b5 (bug 1868374) as requested because it is not yet...
[gecko.git] / accessible / xul / XULTabAccessible.cpp
blobd49395eeb4980f1f4476ebe822e93dd87328f926
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"
8 #include "ARIAMap.h"
9 #include "nsAccUtils.h"
10 #include "Relation.h"
11 #include "mozilla/a11y/Role.h"
12 #include "States.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 ////////////////////////////////////////////////////////////////////////////////
25 // XULTabAccessible
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);
44 if (tab) {
45 tab->Click(mozilla::dom::CallerType::System);
46 return true;
49 return false;
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();
66 if (tab) {
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;
78 return state;
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.
91 ErrorResult rv;
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);
104 return rel;
107 void XULTabAccessible::ApplyARIAState(uint64_t* aState) const {
108 HyperTextAccessible::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 ////////////////////////////////////////////////////////////////////////////////
118 // XULTabsAccessible
119 ////////////////////////////////////////////////////////////////////////////////
121 XULTabsAccessible::XULTabsAccessible(nsIContent* aContent, DocAccessible* aDoc)
122 : XULSelectControlAccessible(aContent, aDoc) {}
124 role XULTabsAccessible::NativeRole() const { return roles::PAGETABLIST; }
126 bool XULTabsAccessible::HasPrimaryAction() const { return false; }
128 void XULTabsAccessible::Value(nsString& aValue) const { aValue.Truncate(); }
130 ENameValueFlag XULTabsAccessible::NativeName(nsString& aName) const {
131 // no name
132 return eNameOK;
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.
139 MOZ_ASSERT(Elm());
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<Accessible*>* aItems) {
154 if (nsAccUtils::IsARIAMultiSelectable(this)) {
155 AccessibleWrap::SelectedItems(aItems);
156 } else {
157 XULSelectControlAccessible::SelectedItems(aItems);
161 Accessible* 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,
196 DocAccessible* aDoc)
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);
217 return rel;