Bumping manifests a=b2g-bump
[gecko.git] / accessible / base / ARIAStateMap.cpp
blob30dc0e9f84fd4748af5ca0764bfc35845f5352c6
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "ARIAMap.h"
8 #include "nsAccUtils.h"
9 #include "States.h"
11 #include "mozilla/dom/Element.h"
13 using namespace mozilla;
14 using namespace mozilla::a11y;
15 using namespace mozilla::a11y::aria;
17 /**
18 * Used to store state map rule data for ARIA attribute of enum type.
20 struct EnumTypeData
22 // ARIA attribute name.
23 nsIAtom* const mAttrName;
25 // States if the attribute value is matched to the enum value. Used as
26 // nsIContent::AttrValuesArray, last item must be nullptr.
27 nsIAtom* const* const mValues[4];
29 // States applied if corresponding enum values are matched.
30 const uint64_t mStates[3];
32 // States to clear in case of match.
33 const uint64_t mClearState;
36 enum ETokenType
38 eBoolType = 0,
39 eMixedType = 1, // can take 'mixed' value
40 eDefinedIfAbsent = 2 // permanent and false state are applied if absent
43 /**
44 * Used to store state map rule data for ARIA attribute of token type (including
45 * mixed value).
47 struct TokenTypeData
49 TokenTypeData(nsIAtom* aAttrName, uint32_t aType,
50 uint64_t aPermanentState,
51 uint64_t aTrueState,
52 uint64_t aFalseState = 0) :
53 mAttrName(aAttrName), mType(aType), mPermanentState(aPermanentState),
54 mTrueState(aTrueState), mFalseState(aFalseState)
55 { }
57 // ARIA attribute name.
58 nsIAtom* const mAttrName;
60 // Type.
61 const uint32_t mType;
63 // State applied if the attribute is defined or mType doesn't have
64 // eDefinedIfAbsent flag set.
65 const uint64_t mPermanentState;
67 // States applied if the attribute value is true/false.
68 const uint64_t mTrueState;
69 const uint64_t mFalseState;
72 /**
73 * Map enum type attribute value to accessible state.
75 static void MapEnumType(dom::Element* aElement, uint64_t* aState,
76 const EnumTypeData& aData);
78 /**
79 * Map token type attribute value to states.
81 static void MapTokenType(dom::Element* aContent, uint64_t* aState,
82 const TokenTypeData& aData);
84 bool
85 aria::MapToState(EStateRule aRule, dom::Element* aElement, uint64_t* aState)
87 switch (aRule) {
88 case eARIAAutoComplete:
90 static const EnumTypeData data = {
91 nsGkAtoms::aria_autocomplete,
92 { &nsGkAtoms::inlinevalue,
93 &nsGkAtoms::list,
94 &nsGkAtoms::both, nullptr },
95 { states::SUPPORTS_AUTOCOMPLETION,
96 states::HASPOPUP | states::SUPPORTS_AUTOCOMPLETION,
97 states::HASPOPUP | states::SUPPORTS_AUTOCOMPLETION }, 0
100 MapEnumType(aElement, aState, data);
101 return true;
104 case eARIABusy:
106 static const EnumTypeData data = {
107 nsGkAtoms::aria_busy,
108 { &nsGkAtoms::_true,
109 &nsGkAtoms::error, nullptr },
110 { states::BUSY,
111 states::INVALID }, 0
114 MapEnumType(aElement, aState, data);
115 return true;
118 case eARIACheckableBool:
120 static const TokenTypeData data(
121 nsGkAtoms::aria_checked, eBoolType | eDefinedIfAbsent,
122 states::CHECKABLE, states::CHECKED);
124 MapTokenType(aElement, aState, data);
125 return true;
128 case eARIACheckableMixed:
130 static const TokenTypeData data(
131 nsGkAtoms::aria_checked, eMixedType | eDefinedIfAbsent,
132 states::CHECKABLE, states::CHECKED);
134 MapTokenType(aElement, aState, data);
135 return true;
138 case eARIACheckedMixed:
140 static const TokenTypeData data(
141 nsGkAtoms::aria_checked, eMixedType,
142 states::CHECKABLE, states::CHECKED);
144 MapTokenType(aElement, aState, data);
145 return true;
148 case eARIADisabled:
150 static const TokenTypeData data(
151 nsGkAtoms::aria_disabled, eBoolType,
152 0, states::UNAVAILABLE);
154 MapTokenType(aElement, aState, data);
155 return true;
158 case eARIAExpanded:
160 static const TokenTypeData data(
161 nsGkAtoms::aria_expanded, eBoolType,
162 0, states::EXPANDED, states::COLLAPSED);
164 MapTokenType(aElement, aState, data);
165 return true;
168 case eARIAHasPopup:
170 static const TokenTypeData data(
171 nsGkAtoms::aria_haspopup, eBoolType,
172 0, states::HASPOPUP);
174 MapTokenType(aElement, aState, data);
175 return true;
178 case eARIAInvalid:
180 static const TokenTypeData data(
181 nsGkAtoms::aria_invalid, eBoolType,
182 0, states::INVALID);
184 MapTokenType(aElement, aState, data);
185 return true;
188 case eARIAMultiline:
190 static const TokenTypeData data(
191 nsGkAtoms::aria_multiline, eBoolType | eDefinedIfAbsent,
192 0, states::MULTI_LINE, states::SINGLE_LINE);
194 MapTokenType(aElement, aState, data);
195 return true;
198 case eARIAMultiSelectable:
200 static const TokenTypeData data(
201 nsGkAtoms::aria_multiselectable, eBoolType,
202 0, states::MULTISELECTABLE | states::EXTSELECTABLE);
204 MapTokenType(aElement, aState, data);
205 return true;
208 case eARIAOrientation:
210 static const EnumTypeData data = {
211 nsGkAtoms::aria_orientation,
212 { &nsGkAtoms::horizontal,
213 &nsGkAtoms::vertical, nullptr },
214 { states::HORIZONTAL,
215 states::VERTICAL },
216 states::HORIZONTAL | states::VERTICAL
219 MapEnumType(aElement, aState, data);
220 return true;
223 case eARIAPressed:
225 static const TokenTypeData data(
226 nsGkAtoms::aria_pressed, eMixedType,
227 0, states::PRESSED);
229 MapTokenType(aElement, aState, data);
230 return true;
233 case eARIAReadonly:
235 static const TokenTypeData data(
236 nsGkAtoms::aria_readonly, eBoolType,
237 0, states::READONLY);
239 MapTokenType(aElement, aState, data);
240 return true;
243 case eARIAReadonlyOrEditable:
245 static const TokenTypeData data(
246 nsGkAtoms::aria_readonly, eBoolType | eDefinedIfAbsent,
247 0, states::READONLY, states::EDITABLE);
249 MapTokenType(aElement, aState, data);
250 return true;
253 case eARIAReadonlyOrEditableIfDefined:
255 static const TokenTypeData data(
256 nsGkAtoms::aria_readonly, eBoolType,
257 0, states::READONLY, states::EDITABLE);
259 MapTokenType(aElement, aState, data);
260 return true;
263 case eARIARequired:
265 static const TokenTypeData data(
266 nsGkAtoms::aria_required, eBoolType,
267 0, states::REQUIRED);
269 MapTokenType(aElement, aState, data);
270 return true;
273 case eARIASelectable:
275 static const TokenTypeData data(
276 nsGkAtoms::aria_selected, eBoolType | eDefinedIfAbsent,
277 states::SELECTABLE, states::SELECTED);
279 MapTokenType(aElement, aState, data);
280 return true;
283 case eARIASelectableIfDefined:
285 static const TokenTypeData data(
286 nsGkAtoms::aria_selected, eBoolType,
287 states::SELECTABLE, states::SELECTED);
289 MapTokenType(aElement, aState, data);
290 return true;
293 case eReadonlyUntilEditable:
295 if (!(*aState & states::EDITABLE))
296 *aState |= states::READONLY;
298 return true;
301 case eIndeterminateIfNoValue:
303 if (!aElement->HasAttr(kNameSpaceID_None, nsGkAtoms::aria_valuenow) &&
304 !aElement->HasAttr(kNameSpaceID_None, nsGkAtoms::aria_valuetext))
305 *aState |= states::MIXED;
307 return true;
310 case eFocusableUntilDisabled:
312 if (!nsAccUtils::HasDefinedARIAToken(aElement, nsGkAtoms::aria_disabled) ||
313 aElement->AttrValueIs(kNameSpaceID_None, nsGkAtoms::aria_disabled,
314 nsGkAtoms::_false, eCaseMatters))
315 *aState |= states::FOCUSABLE;
317 return true;
320 default:
321 return false;
325 static void
326 MapEnumType(dom::Element* aElement, uint64_t* aState, const EnumTypeData& aData)
328 switch (aElement->FindAttrValueIn(kNameSpaceID_None, aData.mAttrName,
329 aData.mValues, eCaseMatters)) {
330 case 0:
331 *aState = (*aState & ~aData.mClearState) | aData.mStates[0];
332 return;
333 case 1:
334 *aState = (*aState & ~aData.mClearState) | aData.mStates[1];
335 return;
336 case 2:
337 *aState = (*aState & ~aData.mClearState) | aData.mStates[2];
338 return;
342 static void
343 MapTokenType(dom::Element* aElement, uint64_t* aState,
344 const TokenTypeData& aData)
346 if (nsAccUtils::HasDefinedARIAToken(aElement, aData.mAttrName)) {
347 if ((aData.mType & eMixedType) &&
348 aElement->AttrValueIs(kNameSpaceID_None, aData.mAttrName,
349 nsGkAtoms::mixed, eCaseMatters)) {
350 *aState |= aData.mPermanentState | states::MIXED;
351 return;
354 if (aElement->AttrValueIs(kNameSpaceID_None, aData.mAttrName,
355 nsGkAtoms::_false, eCaseMatters)) {
356 *aState |= aData.mPermanentState | aData.mFalseState;
357 return;
360 *aState |= aData.mPermanentState | aData.mTrueState;
361 return;
364 if (aData.mType & eDefinedIfAbsent)
365 *aState |= aData.mPermanentState | aData.mFalseState;