accessible/src/base/ARIAStateMap.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* vim: set ts=2 et sw=2 tw=80: */
michael@0 3 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
michael@0 5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 #include "ARIAMap.h"
michael@0 8 #include "nsAccUtils.h"
michael@0 9 #include "States.h"
michael@0 10
michael@0 11 #include "mozilla/dom/Element.h"
michael@0 12
michael@0 13 using namespace mozilla;
michael@0 14 using namespace mozilla::a11y;
michael@0 15 using namespace mozilla::a11y::aria;
michael@0 16
michael@0 17 /**
michael@0 18 * Used to store state map rule data for ARIA attribute of enum type.
michael@0 19 */
michael@0 20 struct EnumTypeData
michael@0 21 {
michael@0 22 EnumTypeData(nsIAtom* aAttrName,
michael@0 23 nsIAtom** aValue1, uint64_t aState1,
michael@0 24 nsIAtom** aValue2, uint64_t aState2,
michael@0 25 nsIAtom** aValue3 = 0, uint64_t aState3 = 0) :
michael@0 26 mState1(aState1), mState2(aState2), mState3(aState3), mDefaultState(0),
michael@0 27 mAttrName(aAttrName), mValue1(aValue1), mValue2(aValue2), mValue3(aValue3),
michael@0 28 mNullValue(nullptr)
michael@0 29 { }
michael@0 30
michael@0 31 EnumTypeData(nsIAtom* aAttrName, uint64_t aDefaultState,
michael@0 32 nsIAtom** aValue1, uint64_t aState1) :
michael@0 33 mState1(aState1), mState2(0), mState3(0), mDefaultState(aDefaultState),
michael@0 34 mAttrName(aAttrName), mValue1(aValue1), mValue2(nullptr), mValue3(nullptr),
michael@0 35 mNullValue(nullptr)
michael@0 36 { }
michael@0 37
michael@0 38 // States applied if corresponding enum values are matched.
michael@0 39 const uint64_t mState1;
michael@0 40 const uint64_t mState2;
michael@0 41 const uint64_t mState3;
michael@0 42
michael@0 43 // Default state if no one enum value is matched.
michael@0 44 const uint64_t mDefaultState;
michael@0 45
michael@0 46 // ARIA attribute name.
michael@0 47 nsIAtom* const mAttrName;
michael@0 48
michael@0 49 // States if the attribute value is matched to the enum value. Used as
michael@0 50 // nsIContent::AttrValuesArray.
michael@0 51 nsIAtom* const* const mValue1;
michael@0 52 nsIAtom* const* const mValue2;
michael@0 53 nsIAtom* const* const mValue3;
michael@0 54 nsIAtom* const* const mNullValue;
michael@0 55 };
michael@0 56
michael@0 57 enum ETokenType
michael@0 58 {
michael@0 59 eBoolType = 0,
michael@0 60 eMixedType = 1, // can take 'mixed' value
michael@0 61 eDefinedIfAbsent = 2 // permanent and false state are applied if absent
michael@0 62 };
michael@0 63
michael@0 64 /**
michael@0 65 * Used to store state map rule data for ARIA attribute of token type (including
michael@0 66 * mixed value).
michael@0 67 */
michael@0 68 struct TokenTypeData
michael@0 69 {
michael@0 70 TokenTypeData(nsIAtom* aAttrName, uint32_t aType,
michael@0 71 uint64_t aPermanentState,
michael@0 72 uint64_t aTrueState,
michael@0 73 uint64_t aFalseState = 0) :
michael@0 74 mAttrName(aAttrName), mType(aType), mPermanentState(aPermanentState),
michael@0 75 mTrueState(aTrueState), mFalseState(aFalseState)
michael@0 76 { }
michael@0 77
michael@0 78 // ARIA attribute name.
michael@0 79 nsIAtom* const mAttrName;
michael@0 80
michael@0 81 // Type.
michael@0 82 const uint32_t mType;
michael@0 83
michael@0 84 // State applied if the attribute is defined or mType doesn't have
michael@0 85 // eDefinedIfAbsent flag set.
michael@0 86 const uint64_t mPermanentState;
michael@0 87
michael@0 88 // States applied if the attribute value is true/false.
michael@0 89 const uint64_t mTrueState;
michael@0 90 const uint64_t mFalseState;
michael@0 91 };
michael@0 92
michael@0 93 /**
michael@0 94 * Map enum type attribute value to accessible state.
michael@0 95 */
michael@0 96 static void MapEnumType(dom::Element* aElement, uint64_t* aState,
michael@0 97 const EnumTypeData& aData);
michael@0 98
michael@0 99 /**
michael@0 100 * Map token type attribute value to states.
michael@0 101 */
michael@0 102 static void MapTokenType(dom::Element* aContent, uint64_t* aState,
michael@0 103 const TokenTypeData& aData);
michael@0 104
michael@0 105 bool
michael@0 106 aria::MapToState(EStateRule aRule, dom::Element* aElement, uint64_t* aState)
michael@0 107 {
michael@0 108 switch (aRule) {
michael@0 109 case eARIAAutoComplete:
michael@0 110 {
michael@0 111 static const EnumTypeData data(
michael@0 112 nsGkAtoms::aria_autocomplete,
michael@0 113 &nsGkAtoms::inlinevalue, states::SUPPORTS_AUTOCOMPLETION,
michael@0 114 &nsGkAtoms::list, states::HASPOPUP | states::SUPPORTS_AUTOCOMPLETION,
michael@0 115 &nsGkAtoms::both, states::HASPOPUP | states::SUPPORTS_AUTOCOMPLETION);
michael@0 116
michael@0 117 MapEnumType(aElement, aState, data);
michael@0 118 return true;
michael@0 119 }
michael@0 120
michael@0 121 case eARIABusy:
michael@0 122 {
michael@0 123 static const EnumTypeData data(
michael@0 124 nsGkAtoms::aria_busy,
michael@0 125 &nsGkAtoms::_true, states::BUSY,
michael@0 126 &nsGkAtoms::error, states::INVALID);
michael@0 127
michael@0 128 MapEnumType(aElement, aState, data);
michael@0 129 return true;
michael@0 130 }
michael@0 131
michael@0 132 case eARIACheckableBool:
michael@0 133 {
michael@0 134 static const TokenTypeData data(
michael@0 135 nsGkAtoms::aria_checked, eBoolType | eDefinedIfAbsent,
michael@0 136 states::CHECKABLE, states::CHECKED);
michael@0 137
michael@0 138 MapTokenType(aElement, aState, data);
michael@0 139 return true;
michael@0 140 }
michael@0 141
michael@0 142 case eARIACheckableMixed:
michael@0 143 {
michael@0 144 static const TokenTypeData data(
michael@0 145 nsGkAtoms::aria_checked, eMixedType | eDefinedIfAbsent,
michael@0 146 states::CHECKABLE, states::CHECKED);
michael@0 147
michael@0 148 MapTokenType(aElement, aState, data);
michael@0 149 return true;
michael@0 150 }
michael@0 151
michael@0 152 case eARIACheckedMixed:
michael@0 153 {
michael@0 154 static const TokenTypeData data(
michael@0 155 nsGkAtoms::aria_checked, eMixedType,
michael@0 156 states::CHECKABLE, states::CHECKED);
michael@0 157
michael@0 158 MapTokenType(aElement, aState, data);
michael@0 159 return true;
michael@0 160 }
michael@0 161
michael@0 162 case eARIADisabled:
michael@0 163 {
michael@0 164 static const TokenTypeData data(
michael@0 165 nsGkAtoms::aria_disabled, eBoolType,
michael@0 166 0, states::UNAVAILABLE);
michael@0 167
michael@0 168 MapTokenType(aElement, aState, data);
michael@0 169 return true;
michael@0 170 }
michael@0 171
michael@0 172 case eARIAExpanded:
michael@0 173 {
michael@0 174 static const TokenTypeData data(
michael@0 175 nsGkAtoms::aria_expanded, eBoolType,
michael@0 176 0, states::EXPANDED, states::COLLAPSED);
michael@0 177
michael@0 178 MapTokenType(aElement, aState, data);
michael@0 179 return true;
michael@0 180 }
michael@0 181
michael@0 182 case eARIAHasPopup:
michael@0 183 {
michael@0 184 static const TokenTypeData data(
michael@0 185 nsGkAtoms::aria_haspopup, eBoolType,
michael@0 186 0, states::HASPOPUP);
michael@0 187
michael@0 188 MapTokenType(aElement, aState, data);
michael@0 189 return true;
michael@0 190 }
michael@0 191
michael@0 192 case eARIAInvalid:
michael@0 193 {
michael@0 194 static const TokenTypeData data(
michael@0 195 nsGkAtoms::aria_invalid, eBoolType,
michael@0 196 0, states::INVALID);
michael@0 197
michael@0 198 MapTokenType(aElement, aState, data);
michael@0 199 return true;
michael@0 200 }
michael@0 201
michael@0 202 case eARIAMultiline:
michael@0 203 {
michael@0 204 static const TokenTypeData data(
michael@0 205 nsGkAtoms::aria_multiline, eBoolType | eDefinedIfAbsent,
michael@0 206 0, states::MULTI_LINE, states::SINGLE_LINE);
michael@0 207
michael@0 208 MapTokenType(aElement, aState, data);
michael@0 209 return true;
michael@0 210 }
michael@0 211
michael@0 212 case eARIAMultiSelectable:
michael@0 213 {
michael@0 214 static const TokenTypeData data(
michael@0 215 nsGkAtoms::aria_multiselectable, eBoolType,
michael@0 216 0, states::MULTISELECTABLE | states::EXTSELECTABLE);
michael@0 217
michael@0 218 MapTokenType(aElement, aState, data);
michael@0 219 return true;
michael@0 220 }
michael@0 221
michael@0 222 case eARIAOrientation:
michael@0 223 {
michael@0 224 if (aElement->AttrValueIs(kNameSpaceID_None, nsGkAtoms::aria_orientation,
michael@0 225 NS_LITERAL_STRING("horizontal"), eCaseMatters)) {
michael@0 226 *aState &= ~states::VERTICAL;
michael@0 227 *aState |= states::HORIZONTAL;
michael@0 228 } else if (aElement->AttrValueIs(kNameSpaceID_None,
michael@0 229 nsGkAtoms::aria_orientation,
michael@0 230 NS_LITERAL_STRING("vertical"),
michael@0 231 eCaseMatters)) {
michael@0 232 *aState &= ~states::HORIZONTAL;
michael@0 233 *aState |= states::VERTICAL;
michael@0 234 } else {
michael@0 235 NS_ASSERTION(!(*aState & (states::HORIZONTAL | states::VERTICAL)),
michael@0 236 "orientation state on role with default aria-orientation!");
michael@0 237 *aState |= GetRoleMap(aElement)->Is(nsGkAtoms::scrollbar) ?
michael@0 238 states::VERTICAL : states::HORIZONTAL;
michael@0 239 }
michael@0 240
michael@0 241 return true;
michael@0 242 }
michael@0 243
michael@0 244 case eARIAPressed:
michael@0 245 {
michael@0 246 static const TokenTypeData data(
michael@0 247 nsGkAtoms::aria_pressed, eMixedType,
michael@0 248 0, states::PRESSED);
michael@0 249
michael@0 250 MapTokenType(aElement, aState, data);
michael@0 251 return true;
michael@0 252 }
michael@0 253
michael@0 254 case eARIAReadonly:
michael@0 255 {
michael@0 256 static const TokenTypeData data(
michael@0 257 nsGkAtoms::aria_readonly, eBoolType,
michael@0 258 0, states::READONLY);
michael@0 259
michael@0 260 MapTokenType(aElement, aState, data);
michael@0 261 return true;
michael@0 262 }
michael@0 263
michael@0 264 case eARIAReadonlyOrEditable:
michael@0 265 {
michael@0 266 static const TokenTypeData data(
michael@0 267 nsGkAtoms::aria_readonly, eBoolType | eDefinedIfAbsent,
michael@0 268 0, states::READONLY, states::EDITABLE);
michael@0 269
michael@0 270 MapTokenType(aElement, aState, data);
michael@0 271 return true;
michael@0 272 }
michael@0 273
michael@0 274 case eARIAReadonlyOrEditableIfDefined:
michael@0 275 {
michael@0 276 static const TokenTypeData data(
michael@0 277 nsGkAtoms::aria_readonly, eBoolType,
michael@0 278 0, states::READONLY, states::EDITABLE);
michael@0 279
michael@0 280 MapTokenType(aElement, aState, data);
michael@0 281 return true;
michael@0 282 }
michael@0 283
michael@0 284 case eARIARequired:
michael@0 285 {
michael@0 286 static const TokenTypeData data(
michael@0 287 nsGkAtoms::aria_required, eBoolType,
michael@0 288 0, states::REQUIRED);
michael@0 289
michael@0 290 MapTokenType(aElement, aState, data);
michael@0 291 return true;
michael@0 292 }
michael@0 293
michael@0 294 case eARIASelectable:
michael@0 295 {
michael@0 296 static const TokenTypeData data(
michael@0 297 nsGkAtoms::aria_selected, eBoolType | eDefinedIfAbsent,
michael@0 298 states::SELECTABLE, states::SELECTED);
michael@0 299
michael@0 300 MapTokenType(aElement, aState, data);
michael@0 301 return true;
michael@0 302 }
michael@0 303
michael@0 304 case eARIASelectableIfDefined:
michael@0 305 {
michael@0 306 static const TokenTypeData data(
michael@0 307 nsGkAtoms::aria_selected, eBoolType,
michael@0 308 states::SELECTABLE, states::SELECTED);
michael@0 309
michael@0 310 MapTokenType(aElement, aState, data);
michael@0 311 return true;
michael@0 312 }
michael@0 313
michael@0 314 case eReadonlyUntilEditable:
michael@0 315 {
michael@0 316 if (!(*aState & states::EDITABLE))
michael@0 317 *aState |= states::READONLY;
michael@0 318
michael@0 319 return true;
michael@0 320 }
michael@0 321
michael@0 322 case eIndeterminateIfNoValue:
michael@0 323 {
michael@0 324 if (!aElement->HasAttr(kNameSpaceID_None, nsGkAtoms::aria_valuenow) &&
michael@0 325 !aElement->HasAttr(kNameSpaceID_None, nsGkAtoms::aria_valuetext))
michael@0 326 *aState |= states::MIXED;
michael@0 327
michael@0 328 return true;
michael@0 329 }
michael@0 330
michael@0 331 case eFocusableUntilDisabled:
michael@0 332 {
michael@0 333 if (!nsAccUtils::HasDefinedARIAToken(aElement, nsGkAtoms::aria_disabled) ||
michael@0 334 aElement->AttrValueIs(kNameSpaceID_None, nsGkAtoms::aria_disabled,
michael@0 335 nsGkAtoms::_false, eCaseMatters))
michael@0 336 *aState |= states::FOCUSABLE;
michael@0 337
michael@0 338 return true;
michael@0 339 }
michael@0 340
michael@0 341 default:
michael@0 342 return false;
michael@0 343 }
michael@0 344 }
michael@0 345
michael@0 346 static void
michael@0 347 MapEnumType(dom::Element* aElement, uint64_t* aState, const EnumTypeData& aData)
michael@0 348 {
michael@0 349 switch (aElement->FindAttrValueIn(kNameSpaceID_None, aData.mAttrName,
michael@0 350 &aData.mValue1, eCaseMatters)) {
michael@0 351 case 0:
michael@0 352 *aState |= aData.mState1;
michael@0 353 return;
michael@0 354 case 1:
michael@0 355 *aState |= aData.mState2;
michael@0 356 return;
michael@0 357 case 2:
michael@0 358 *aState |= aData.mState3;
michael@0 359 return;
michael@0 360 }
michael@0 361
michael@0 362 *aState |= aData.mDefaultState;
michael@0 363 }
michael@0 364
michael@0 365 static void
michael@0 366 MapTokenType(dom::Element* aElement, uint64_t* aState,
michael@0 367 const TokenTypeData& aData)
michael@0 368 {
michael@0 369 if (nsAccUtils::HasDefinedARIAToken(aElement, aData.mAttrName)) {
michael@0 370 if ((aData.mType & eMixedType) &&
michael@0 371 aElement->AttrValueIs(kNameSpaceID_None, aData.mAttrName,
michael@0 372 nsGkAtoms::mixed, eCaseMatters)) {
michael@0 373 *aState |= aData.mPermanentState | states::MIXED;
michael@0 374 return;
michael@0 375 }
michael@0 376
michael@0 377 if (aElement->AttrValueIs(kNameSpaceID_None, aData.mAttrName,
michael@0 378 nsGkAtoms::_false, eCaseMatters)) {
michael@0 379 *aState |= aData.mPermanentState | aData.mFalseState;
michael@0 380 return;
michael@0 381 }
michael@0 382
michael@0 383 *aState |= aData.mPermanentState | aData.mTrueState;
michael@0 384 return;
michael@0 385 }
michael@0 386
michael@0 387 if (aData.mType & eDefinedIfAbsent)
michael@0 388 *aState |= aData.mPermanentState | aData.mFalseState;
michael@0 389 }

mercurial