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/. */
8 #include "nsAccUtils.h"
11 #include "mozilla/dom/Element.h"
13 using namespace mozilla
;
14 using namespace mozilla::a11y
;
15 using namespace mozilla::a11y::aria
;
18 * Used to store state map rule data for ARIA attribute of enum type.
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
;
39 eMixedType
= 1, // can take 'mixed' value
40 eDefinedIfAbsent
= 2 // permanent and false state are applied if absent
44 * Used to store state map rule data for ARIA attribute of token type (including
49 TokenTypeData(nsIAtom
* aAttrName
, uint32_t aType
,
50 uint64_t aPermanentState
,
52 uint64_t aFalseState
= 0) :
53 mAttrName(aAttrName
), mType(aType
), mPermanentState(aPermanentState
),
54 mTrueState(aTrueState
), mFalseState(aFalseState
)
57 // ARIA attribute name.
58 nsIAtom
* const mAttrName
;
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
;
73 * Map enum type attribute value to accessible state.
75 static void MapEnumType(dom::Element
* aElement
, uint64_t* aState
,
76 const EnumTypeData
& aData
);
79 * Map token type attribute value to states.
81 static void MapTokenType(dom::Element
* aContent
, uint64_t* aState
,
82 const TokenTypeData
& aData
);
85 aria::MapToState(EStateRule aRule
, dom::Element
* aElement
, uint64_t* aState
)
88 case eARIAAutoComplete
:
90 static const EnumTypeData data
= {
91 nsGkAtoms::aria_autocomplete
,
92 { &nsGkAtoms::inlinevalue
,
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
);
106 static const EnumTypeData data
= {
107 nsGkAtoms::aria_busy
,
109 &nsGkAtoms::error
, nullptr },
114 MapEnumType(aElement
, aState
, data
);
118 case eARIACheckableBool
:
120 static const TokenTypeData
data(
121 nsGkAtoms::aria_checked
, eBoolType
| eDefinedIfAbsent
,
122 states::CHECKABLE
, states::CHECKED
);
124 MapTokenType(aElement
, aState
, data
);
128 case eARIACheckableMixed
:
130 static const TokenTypeData
data(
131 nsGkAtoms::aria_checked
, eMixedType
| eDefinedIfAbsent
,
132 states::CHECKABLE
, states::CHECKED
);
134 MapTokenType(aElement
, aState
, data
);
138 case eARIACheckedMixed
:
140 static const TokenTypeData
data(
141 nsGkAtoms::aria_checked
, eMixedType
,
142 states::CHECKABLE
, states::CHECKED
);
144 MapTokenType(aElement
, aState
, data
);
150 static const TokenTypeData
data(
151 nsGkAtoms::aria_disabled
, eBoolType
,
152 0, states::UNAVAILABLE
);
154 MapTokenType(aElement
, aState
, data
);
160 static const TokenTypeData
data(
161 nsGkAtoms::aria_expanded
, eBoolType
,
162 0, states::EXPANDED
, states::COLLAPSED
);
164 MapTokenType(aElement
, aState
, data
);
170 static const TokenTypeData
data(
171 nsGkAtoms::aria_haspopup
, eBoolType
,
172 0, states::HASPOPUP
);
174 MapTokenType(aElement
, aState
, data
);
180 static const TokenTypeData
data(
181 nsGkAtoms::aria_invalid
, eBoolType
,
184 MapTokenType(aElement
, aState
, data
);
190 static const TokenTypeData
data(
191 nsGkAtoms::aria_multiline
, eBoolType
| eDefinedIfAbsent
,
192 0, states::MULTI_LINE
, states::SINGLE_LINE
);
194 MapTokenType(aElement
, aState
, data
);
198 case eARIAMultiSelectable
:
200 static const TokenTypeData
data(
201 nsGkAtoms::aria_multiselectable
, eBoolType
,
202 0, states::MULTISELECTABLE
| states::EXTSELECTABLE
);
204 MapTokenType(aElement
, aState
, data
);
208 case eARIAOrientation
:
210 static const EnumTypeData data
= {
211 nsGkAtoms::aria_orientation
,
212 { &nsGkAtoms::horizontal
,
213 &nsGkAtoms::vertical
, nullptr },
214 { states::HORIZONTAL
,
216 states::HORIZONTAL
| states::VERTICAL
219 MapEnumType(aElement
, aState
, data
);
225 static const TokenTypeData
data(
226 nsGkAtoms::aria_pressed
, eMixedType
,
229 MapTokenType(aElement
, aState
, data
);
235 static const TokenTypeData
data(
236 nsGkAtoms::aria_readonly
, eBoolType
,
237 0, states::READONLY
);
239 MapTokenType(aElement
, aState
, data
);
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
);
253 case eARIAReadonlyOrEditableIfDefined
:
255 static const TokenTypeData
data(
256 nsGkAtoms::aria_readonly
, eBoolType
,
257 0, states::READONLY
, states::EDITABLE
);
259 MapTokenType(aElement
, aState
, data
);
265 static const TokenTypeData
data(
266 nsGkAtoms::aria_required
, eBoolType
,
267 0, states::REQUIRED
);
269 MapTokenType(aElement
, aState
, data
);
273 case eARIASelectable
:
275 static const TokenTypeData
data(
276 nsGkAtoms::aria_selected
, eBoolType
| eDefinedIfAbsent
,
277 states::SELECTABLE
, states::SELECTED
);
279 MapTokenType(aElement
, aState
, data
);
283 case eARIASelectableIfDefined
:
285 static const TokenTypeData
data(
286 nsGkAtoms::aria_selected
, eBoolType
,
287 states::SELECTABLE
, states::SELECTED
);
289 MapTokenType(aElement
, aState
, data
);
293 case eReadonlyUntilEditable
:
295 if (!(*aState
& states::EDITABLE
))
296 *aState
|= states::READONLY
;
301 case eIndeterminateIfNoValue
:
303 if (!aElement
->HasAttr(kNameSpaceID_None
, nsGkAtoms::aria_valuenow
) &&
304 !aElement
->HasAttr(kNameSpaceID_None
, nsGkAtoms::aria_valuetext
))
305 *aState
|= states::MIXED
;
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
;
326 MapEnumType(dom::Element
* aElement
, uint64_t* aState
, const EnumTypeData
& aData
)
328 switch (aElement
->FindAttrValueIn(kNameSpaceID_None
, aData
.mAttrName
,
329 aData
.mValues
, eCaseMatters
)) {
331 *aState
= (*aState
& ~aData
.mClearState
) | aData
.mStates
[0];
334 *aState
= (*aState
& ~aData
.mClearState
) | aData
.mStates
[1];
337 *aState
= (*aState
& ~aData
.mClearState
) | aData
.mStates
[2];
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
;
354 if (aElement
->AttrValueIs(kNameSpaceID_None
, aData
.mAttrName
,
355 nsGkAtoms::_false
, eCaseMatters
)) {
356 *aState
|= aData
.mPermanentState
| aData
.mFalseState
;
360 *aState
|= aData
.mPermanentState
| aData
.mTrueState
;
364 if (aData
.mType
& eDefinedIfAbsent
)
365 *aState
|= aData
.mPermanentState
| aData
.mFalseState
;