accessible/src/base/ARIAStateMap.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     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.
    19  */
    20 struct EnumTypeData
    21 {
    22   EnumTypeData(nsIAtom* aAttrName,
    23                nsIAtom** aValue1, uint64_t aState1,
    24                nsIAtom** aValue2, uint64_t aState2,
    25                nsIAtom** aValue3 = 0, uint64_t aState3 = 0) :
    26     mState1(aState1), mState2(aState2), mState3(aState3), mDefaultState(0),
    27     mAttrName(aAttrName), mValue1(aValue1), mValue2(aValue2), mValue3(aValue3),
    28     mNullValue(nullptr)
    29   { }
    31   EnumTypeData(nsIAtom* aAttrName, uint64_t aDefaultState,
    32                nsIAtom** aValue1, uint64_t aState1) :
    33     mState1(aState1), mState2(0), mState3(0), mDefaultState(aDefaultState),
    34     mAttrName(aAttrName), mValue1(aValue1), mValue2(nullptr), mValue3(nullptr),
    35     mNullValue(nullptr)
    36   { }
    38   // States applied if corresponding enum values are matched.
    39   const uint64_t mState1;
    40   const uint64_t mState2;
    41   const uint64_t mState3;
    43   // Default state if no one enum value is matched.
    44   const uint64_t mDefaultState;
    46   // ARIA attribute name.
    47   nsIAtom* const mAttrName;
    49   // States if the attribute value is matched to the enum value. Used as
    50   // nsIContent::AttrValuesArray.
    51   nsIAtom* const* const mValue1;
    52   nsIAtom* const* const mValue2;
    53   nsIAtom* const* const mValue3;
    54   nsIAtom* const* const mNullValue;
    55 };
    57 enum ETokenType
    58 {
    59   eBoolType = 0,
    60   eMixedType = 1, // can take 'mixed' value
    61   eDefinedIfAbsent = 2 // permanent and false state are applied if absent
    62 };
    64 /**
    65  * Used to store state map rule data for ARIA attribute of token type (including
    66  * mixed value).
    67  */
    68 struct TokenTypeData
    69 {
    70   TokenTypeData(nsIAtom* aAttrName, uint32_t aType,
    71                 uint64_t aPermanentState,
    72                 uint64_t aTrueState,
    73                 uint64_t aFalseState = 0) :
    74   mAttrName(aAttrName), mType(aType), mPermanentState(aPermanentState),
    75   mTrueState(aTrueState), mFalseState(aFalseState)
    76   { }
    78   // ARIA attribute name.
    79   nsIAtom* const mAttrName;
    81   // Type.
    82   const uint32_t mType;
    84   // State applied if the attribute is defined or mType doesn't have
    85   // eDefinedIfAbsent flag set.
    86   const uint64_t mPermanentState;
    88   // States applied if the attribute value is true/false.
    89   const uint64_t mTrueState;
    90   const uint64_t mFalseState;
    91 };
    93 /**
    94  * Map enum type attribute value to accessible state.
    95  */
    96 static void MapEnumType(dom::Element* aElement, uint64_t* aState,
    97                         const EnumTypeData& aData);
    99 /**
   100  * Map token type attribute value to states.
   101  */
   102 static void MapTokenType(dom::Element* aContent, uint64_t* aState,
   103                          const TokenTypeData& aData);
   105 bool
   106 aria::MapToState(EStateRule aRule, dom::Element* aElement, uint64_t* aState)
   107 {
   108   switch (aRule) {
   109     case eARIAAutoComplete:
   110     {
   111       static const EnumTypeData data(
   112         nsGkAtoms::aria_autocomplete,
   113         &nsGkAtoms::inlinevalue, states::SUPPORTS_AUTOCOMPLETION,
   114         &nsGkAtoms::list, states::HASPOPUP | states::SUPPORTS_AUTOCOMPLETION,
   115         &nsGkAtoms::both, states::HASPOPUP | states::SUPPORTS_AUTOCOMPLETION);
   117       MapEnumType(aElement, aState, data);
   118       return true;
   119     }
   121     case eARIABusy:
   122     {
   123       static const EnumTypeData data(
   124         nsGkAtoms::aria_busy,
   125         &nsGkAtoms::_true, states::BUSY,
   126         &nsGkAtoms::error, states::INVALID);
   128       MapEnumType(aElement, aState, data);
   129       return true;
   130     }
   132     case eARIACheckableBool:
   133     {
   134       static const TokenTypeData data(
   135         nsGkAtoms::aria_checked, eBoolType | eDefinedIfAbsent,
   136         states::CHECKABLE, states::CHECKED);
   138       MapTokenType(aElement, aState, data);
   139       return true;
   140     }
   142     case eARIACheckableMixed:
   143     {
   144       static const TokenTypeData data(
   145         nsGkAtoms::aria_checked, eMixedType | eDefinedIfAbsent,
   146         states::CHECKABLE, states::CHECKED);
   148       MapTokenType(aElement, aState, data);
   149       return true;
   150     }
   152     case eARIACheckedMixed:
   153     {
   154       static const TokenTypeData data(
   155         nsGkAtoms::aria_checked, eMixedType,
   156         states::CHECKABLE, states::CHECKED);
   158       MapTokenType(aElement, aState, data);
   159       return true;
   160     }
   162     case eARIADisabled:
   163     {
   164       static const TokenTypeData data(
   165         nsGkAtoms::aria_disabled, eBoolType,
   166         0, states::UNAVAILABLE);
   168       MapTokenType(aElement, aState, data);
   169       return true;
   170     }
   172     case eARIAExpanded:
   173     {
   174       static const TokenTypeData data(
   175         nsGkAtoms::aria_expanded, eBoolType,
   176         0, states::EXPANDED, states::COLLAPSED);
   178       MapTokenType(aElement, aState, data);
   179       return true;
   180     }
   182     case eARIAHasPopup:
   183     {
   184       static const TokenTypeData data(
   185         nsGkAtoms::aria_haspopup, eBoolType,
   186         0, states::HASPOPUP);
   188       MapTokenType(aElement, aState, data);
   189       return true;
   190     }
   192     case eARIAInvalid:
   193     {
   194       static const TokenTypeData data(
   195         nsGkAtoms::aria_invalid, eBoolType,
   196         0, states::INVALID);
   198       MapTokenType(aElement, aState, data);
   199       return true;
   200     }
   202     case eARIAMultiline:
   203     {
   204       static const TokenTypeData data(
   205         nsGkAtoms::aria_multiline, eBoolType | eDefinedIfAbsent,
   206         0, states::MULTI_LINE, states::SINGLE_LINE);
   208       MapTokenType(aElement, aState, data);
   209       return true;
   210     }
   212     case eARIAMultiSelectable:
   213     {
   214       static const TokenTypeData data(
   215         nsGkAtoms::aria_multiselectable, eBoolType,
   216         0, states::MULTISELECTABLE | states::EXTSELECTABLE);
   218       MapTokenType(aElement, aState, data);
   219       return true;
   220     }
   222     case eARIAOrientation:
   223     {
   224       if (aElement->AttrValueIs(kNameSpaceID_None, nsGkAtoms::aria_orientation,
   225                                 NS_LITERAL_STRING("horizontal"), eCaseMatters)) {
   226         *aState &= ~states::VERTICAL;
   227         *aState |= states::HORIZONTAL;
   228       } else if (aElement->AttrValueIs(kNameSpaceID_None,
   229                                        nsGkAtoms::aria_orientation,
   230                                        NS_LITERAL_STRING("vertical"),
   231                                        eCaseMatters)) {
   232         *aState &= ~states::HORIZONTAL;
   233         *aState |= states::VERTICAL;
   234       } else {
   235         NS_ASSERTION(!(*aState & (states::HORIZONTAL | states::VERTICAL)),
   236                      "orientation state on role with default aria-orientation!");
   237         *aState |= GetRoleMap(aElement)->Is(nsGkAtoms::scrollbar) ?
   238           states::VERTICAL : states::HORIZONTAL;
   239       }
   241       return true;
   242     }
   244     case eARIAPressed:
   245     {
   246       static const TokenTypeData data(
   247         nsGkAtoms::aria_pressed, eMixedType,
   248         0, states::PRESSED);
   250       MapTokenType(aElement, aState, data);
   251       return true;
   252     }
   254     case eARIAReadonly:
   255     {
   256       static const TokenTypeData data(
   257         nsGkAtoms::aria_readonly, eBoolType,
   258         0, states::READONLY);
   260       MapTokenType(aElement, aState, data);
   261       return true;
   262     }
   264     case eARIAReadonlyOrEditable:
   265     {
   266       static const TokenTypeData data(
   267         nsGkAtoms::aria_readonly, eBoolType | eDefinedIfAbsent,
   268         0, states::READONLY, states::EDITABLE);
   270       MapTokenType(aElement, aState, data);
   271       return true;
   272     }
   274     case eARIAReadonlyOrEditableIfDefined:
   275     {
   276       static const TokenTypeData data(
   277         nsGkAtoms::aria_readonly, eBoolType,
   278         0, states::READONLY, states::EDITABLE);
   280       MapTokenType(aElement, aState, data);
   281       return true;
   282     }
   284     case eARIARequired:
   285     {
   286       static const TokenTypeData data(
   287         nsGkAtoms::aria_required, eBoolType,
   288         0, states::REQUIRED);
   290       MapTokenType(aElement, aState, data);
   291       return true;
   292     }
   294     case eARIASelectable:
   295     {
   296       static const TokenTypeData data(
   297         nsGkAtoms::aria_selected, eBoolType | eDefinedIfAbsent,
   298         states::SELECTABLE, states::SELECTED);
   300       MapTokenType(aElement, aState, data);
   301       return true;
   302     }
   304     case eARIASelectableIfDefined:
   305     {
   306       static const TokenTypeData data(
   307         nsGkAtoms::aria_selected, eBoolType,
   308         states::SELECTABLE, states::SELECTED);
   310       MapTokenType(aElement, aState, data);
   311       return true;
   312     }
   314     case eReadonlyUntilEditable:
   315     {
   316       if (!(*aState & states::EDITABLE))
   317         *aState |= states::READONLY;
   319       return true;
   320     }
   322     case eIndeterminateIfNoValue:
   323     {
   324       if (!aElement->HasAttr(kNameSpaceID_None, nsGkAtoms::aria_valuenow) &&
   325           !aElement->HasAttr(kNameSpaceID_None, nsGkAtoms::aria_valuetext))
   326         *aState |= states::MIXED;
   328       return true;
   329     }
   331     case eFocusableUntilDisabled:
   332     {
   333       if (!nsAccUtils::HasDefinedARIAToken(aElement, nsGkAtoms::aria_disabled) ||
   334           aElement->AttrValueIs(kNameSpaceID_None, nsGkAtoms::aria_disabled,
   335                                 nsGkAtoms::_false, eCaseMatters))
   336         *aState |= states::FOCUSABLE;
   338       return true;
   339     }
   341     default:
   342       return false;
   343   }
   344 }
   346 static void
   347 MapEnumType(dom::Element* aElement, uint64_t* aState, const EnumTypeData& aData)
   348 {
   349   switch (aElement->FindAttrValueIn(kNameSpaceID_None, aData.mAttrName,
   350                                     &aData.mValue1, eCaseMatters)) {
   351     case 0:
   352       *aState |= aData.mState1;
   353       return;
   354     case 1:
   355       *aState |= aData.mState2;
   356       return;
   357     case 2:
   358       *aState |= aData.mState3;
   359       return;
   360   }
   362   *aState |= aData.mDefaultState;
   363 }
   365 static void
   366 MapTokenType(dom::Element* aElement, uint64_t* aState,
   367              const TokenTypeData& aData)
   368 {
   369   if (nsAccUtils::HasDefinedARIAToken(aElement, aData.mAttrName)) {
   370     if ((aData.mType & eMixedType) &&
   371         aElement->AttrValueIs(kNameSpaceID_None, aData.mAttrName,
   372                               nsGkAtoms::mixed, eCaseMatters)) {
   373       *aState |= aData.mPermanentState | states::MIXED;
   374       return;
   375     }
   377     if (aElement->AttrValueIs(kNameSpaceID_None, aData.mAttrName,
   378                               nsGkAtoms::_false, eCaseMatters)) {
   379       *aState |= aData.mPermanentState | aData.mFalseState;
   380       return;
   381     }
   383     *aState |= aData.mPermanentState | aData.mTrueState;
   384     return;
   385   }
   387   if (aData.mType & eDefinedIfAbsent)
   388     *aState |= aData.mPermanentState | aData.mFalseState;
   389 }

mercurial