mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-27 04:38:02 +00:00
Bug 741398 - make ARIA state map extensible, r=tbsaunde
This commit is contained in:
parent
80f0b96a3a
commit
01482115ce
343
accessible/src/base/ARIAStateMap.cpp
Normal file
343
accessible/src/base/ARIAStateMap.cpp
Normal file
@ -0,0 +1,343 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "ARIAStateMap.h"
|
||||
|
||||
#include "States.h"
|
||||
|
||||
#include "mozilla/dom/Element.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::a11y;
|
||||
using namespace mozilla::a11y::aria;
|
||||
|
||||
/**
|
||||
* Used to store state map rule data for ARIA attribute of enum type.
|
||||
*/
|
||||
struct EnumTypeData
|
||||
{
|
||||
EnumTypeData(nsIAtom* aAttrName,
|
||||
nsIAtom** aValue1, PRUint64 aState1,
|
||||
nsIAtom** aValue2, PRUint64 aState2,
|
||||
nsIAtom** aValue3 = 0, PRUint64 aState3 = 0) :
|
||||
mState1(aState1), mState2(aState2), mState3(aState3), mDefaultState(0),
|
||||
mAttrName(aAttrName), mValue1(aValue1), mValue2(aValue2), mValue3(aValue3),
|
||||
mNullValue(nsnull)
|
||||
{ }
|
||||
|
||||
EnumTypeData(nsIAtom* aAttrName, PRUint64 aDefaultState,
|
||||
nsIAtom** aValue1, PRUint64 aState1) :
|
||||
mState1(aState1), mState2(0), mState3(0), mDefaultState(aDefaultState),
|
||||
mAttrName(aAttrName), mValue1(aValue1), mValue2(nsnull), mValue3(nsnull),
|
||||
mNullValue(nsnull)
|
||||
{ }
|
||||
|
||||
// States applied if corresponding enum values are matched.
|
||||
const PRUint64 mState1;
|
||||
const PRUint64 mState2;
|
||||
const PRUint64 mState3;
|
||||
|
||||
// Default state if no one enum value is matched.
|
||||
const PRUint64 mDefaultState;
|
||||
|
||||
// ARIA attribute name.
|
||||
nsIAtom* const mAttrName;
|
||||
|
||||
// States if the attribute value is matched to the enum value. Used as
|
||||
// nsIContent::AttrValuesArray.
|
||||
nsIAtom* const* const mValue1;
|
||||
nsIAtom* const* const mValue2;
|
||||
nsIAtom* const* const mValue3;
|
||||
nsIAtom* const* const mNullValue;
|
||||
};
|
||||
|
||||
enum ETokenType
|
||||
{
|
||||
eBoolType = 0,
|
||||
eMixedType = 1, // can take 'mixed' value
|
||||
eDefinedIfAbsent = 2 // permanent and false state are applied if absent
|
||||
};
|
||||
|
||||
/**
|
||||
* Used to store state map rule data for ARIA attribute of token type (including
|
||||
* mixed value).
|
||||
*/
|
||||
struct TokenTypeData
|
||||
{
|
||||
TokenTypeData(nsIAtom* aAttrName, PRUint32 aType,
|
||||
PRUint64 aPermanentState,
|
||||
PRUint64 aTrueState,
|
||||
PRUint64 aFalseState = 0) :
|
||||
mAttrName(aAttrName), mType(aType), mPermanentState(aPermanentState),
|
||||
mTrueState(aTrueState), mFalseState(aFalseState)
|
||||
{ }
|
||||
|
||||
// ARIA attribute name.
|
||||
nsIAtom* const mAttrName;
|
||||
|
||||
// Type.
|
||||
const PRUint32 mType;
|
||||
|
||||
// State applied if the attribute is defined or mType doesn't have
|
||||
// eDefinedIfAbsent flag set.
|
||||
const PRUint64 mPermanentState;
|
||||
|
||||
// States applied if the attribute value is true/false.
|
||||
const PRUint64 mTrueState;
|
||||
const PRUint64 mFalseState;
|
||||
};
|
||||
|
||||
/**
|
||||
* Map enum type attribute value to accessible state.
|
||||
*/
|
||||
static void MapEnumType(dom::Element* aElement, PRUint64* aState,
|
||||
const EnumTypeData& aData);
|
||||
|
||||
/**
|
||||
* Map token type attribute value to states.
|
||||
*/
|
||||
static void MapTokenType(dom::Element* aContent, PRUint64* aState,
|
||||
const TokenTypeData& aData);
|
||||
|
||||
bool
|
||||
aria::MapToState(EStateRule aRule, dom::Element* aElement, PRUint64* aState)
|
||||
{
|
||||
switch (aRule) {
|
||||
case eARIAAutoComplete:
|
||||
{
|
||||
static const EnumTypeData data(
|
||||
nsGkAtoms::aria_autocomplete,
|
||||
&nsGkAtoms::inlinevalue, states::SUPPORTS_AUTOCOMPLETION,
|
||||
&nsGkAtoms::list, states::HASPOPUP | states::SUPPORTS_AUTOCOMPLETION,
|
||||
&nsGkAtoms::both, states::HASPOPUP | states::SUPPORTS_AUTOCOMPLETION);
|
||||
|
||||
MapEnumType(aElement, aState, data);
|
||||
return true;
|
||||
}
|
||||
|
||||
case eARIABusy:
|
||||
{
|
||||
static const EnumTypeData data(
|
||||
nsGkAtoms::aria_busy,
|
||||
&nsGkAtoms::_true, states::BUSY,
|
||||
&nsGkAtoms::error, states::INVALID);
|
||||
|
||||
MapEnumType(aElement, aState, data);
|
||||
return true;
|
||||
}
|
||||
|
||||
case eARIACheckableBool:
|
||||
{
|
||||
static const TokenTypeData data(
|
||||
nsGkAtoms::aria_checked, eBoolType | eDefinedIfAbsent,
|
||||
states::CHECKABLE, states::CHECKED);
|
||||
|
||||
MapTokenType(aElement, aState, data);
|
||||
return true;
|
||||
}
|
||||
|
||||
case eARIACheckableMixed:
|
||||
{
|
||||
static const TokenTypeData data(
|
||||
nsGkAtoms::aria_checked, eMixedType | eDefinedIfAbsent,
|
||||
states::CHECKABLE, states::CHECKED);
|
||||
|
||||
MapTokenType(aElement, aState, data);
|
||||
return true;
|
||||
}
|
||||
|
||||
case eARIACheckedMixed:
|
||||
{
|
||||
static const TokenTypeData data(
|
||||
nsGkAtoms::aria_checked, eMixedType,
|
||||
states::CHECKABLE, states::CHECKED);
|
||||
|
||||
MapTokenType(aElement, aState, data);
|
||||
return true;
|
||||
}
|
||||
|
||||
case eARIADisabled:
|
||||
{
|
||||
static const TokenTypeData data(
|
||||
nsGkAtoms::aria_disabled, eBoolType,
|
||||
0, states::UNAVAILABLE);
|
||||
|
||||
MapTokenType(aElement, aState, data);
|
||||
return true;
|
||||
}
|
||||
|
||||
case eARIAExpanded:
|
||||
{
|
||||
static const TokenTypeData data(
|
||||
nsGkAtoms::aria_expanded, eBoolType,
|
||||
0, states::EXPANDED, states::COLLAPSED);
|
||||
|
||||
MapTokenType(aElement, aState, data);
|
||||
return true;
|
||||
}
|
||||
|
||||
case eARIAHasPopup:
|
||||
{
|
||||
static const TokenTypeData data(
|
||||
nsGkAtoms::aria_haspopup, eBoolType,
|
||||
0, states::HASPOPUP);
|
||||
|
||||
MapTokenType(aElement, aState, data);
|
||||
return true;
|
||||
}
|
||||
|
||||
case eARIAInvalid:
|
||||
{
|
||||
static const TokenTypeData data(
|
||||
nsGkAtoms::aria_invalid, eBoolType,
|
||||
0, states::INVALID);
|
||||
|
||||
MapTokenType(aElement, aState, data);
|
||||
return true;
|
||||
}
|
||||
|
||||
case eARIAMultiline:
|
||||
{
|
||||
static const TokenTypeData data(
|
||||
nsGkAtoms::aria_multiline, eBoolType | eDefinedIfAbsent,
|
||||
0, states::MULTI_LINE, states::SINGLE_LINE);
|
||||
|
||||
MapTokenType(aElement, aState, data);
|
||||
return true;
|
||||
}
|
||||
|
||||
case eARIAMultiSelectable:
|
||||
{
|
||||
static const TokenTypeData data(
|
||||
nsGkAtoms::aria_multiselectable, eBoolType,
|
||||
0, states::MULTISELECTABLE | states::EXTSELECTABLE);
|
||||
|
||||
MapTokenType(aElement, aState, data);
|
||||
return true;
|
||||
}
|
||||
|
||||
case eARIAOrientation:
|
||||
{
|
||||
static const EnumTypeData data(
|
||||
nsGkAtoms::aria_orientation, states::HORIZONTAL,
|
||||
&nsGkAtoms::vertical, states::VERTICAL);
|
||||
|
||||
MapEnumType(aElement, aState, data);
|
||||
return true;
|
||||
}
|
||||
|
||||
case eARIAPressed:
|
||||
{
|
||||
static const TokenTypeData data(
|
||||
nsGkAtoms::aria_pressed, eMixedType,
|
||||
states::CHECKABLE, states::PRESSED);
|
||||
|
||||
MapTokenType(aElement, aState, data);
|
||||
return true;
|
||||
}
|
||||
|
||||
case eARIAReadonly:
|
||||
{
|
||||
static const TokenTypeData data(
|
||||
nsGkAtoms::aria_readonly, eBoolType,
|
||||
0, states::READONLY);
|
||||
|
||||
MapTokenType(aElement, aState, data);
|
||||
return true;
|
||||
}
|
||||
|
||||
case eARIAReadonlyOrEditable:
|
||||
{
|
||||
static const TokenTypeData data(
|
||||
nsGkAtoms::aria_readonly, eBoolType | eDefinedIfAbsent,
|
||||
0, states::READONLY, states::EDITABLE);
|
||||
|
||||
MapTokenType(aElement, aState, data);
|
||||
return true;
|
||||
}
|
||||
|
||||
case eARIARequired:
|
||||
{
|
||||
static const TokenTypeData data(
|
||||
nsGkAtoms::aria_required, eBoolType,
|
||||
0, states::REQUIRED);
|
||||
|
||||
MapTokenType(aElement, aState, data);
|
||||
return true;
|
||||
}
|
||||
|
||||
case eARIASelectable:
|
||||
{
|
||||
static const TokenTypeData data(
|
||||
nsGkAtoms::aria_selected, eBoolType | eDefinedIfAbsent,
|
||||
states::SELECTABLE, states::SELECTED);
|
||||
|
||||
MapTokenType(aElement, aState, data);
|
||||
return true;
|
||||
}
|
||||
|
||||
case eReadonlyUntilEditable:
|
||||
{
|
||||
if (!(*aState & states::EDITABLE))
|
||||
*aState |= states::READONLY;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
MapEnumType(dom::Element* aElement, PRUint64* aState, const EnumTypeData& aData)
|
||||
{
|
||||
switch (aElement->FindAttrValueIn(kNameSpaceID_None, aData.mAttrName,
|
||||
&aData.mValue1, eCaseMatters)) {
|
||||
case 0:
|
||||
*aState |= aData.mState1;
|
||||
return;
|
||||
case 1:
|
||||
*aState |= aData.mState2;
|
||||
return;
|
||||
case 2:
|
||||
*aState |= aData.mState3;
|
||||
return;
|
||||
}
|
||||
|
||||
*aState |= aData.mDefaultState;
|
||||
}
|
||||
|
||||
static void
|
||||
MapTokenType(dom::Element* aElement, PRUint64* aState,
|
||||
const TokenTypeData& aData)
|
||||
{
|
||||
if (aElement->HasAttr(kNameSpaceID_None, aData.mAttrName)) {
|
||||
if ((aData.mType & eMixedType) &&
|
||||
aElement->AttrValueIs(kNameSpaceID_None, aData.mAttrName,
|
||||
nsGkAtoms::mixed, eCaseMatters)) {
|
||||
*aState |= aData.mPermanentState | states::MIXED;
|
||||
return;
|
||||
}
|
||||
|
||||
if (aElement->AttrValueIs(kNameSpaceID_None, aData.mAttrName,
|
||||
nsGkAtoms::_false, eCaseMatters)) {
|
||||
*aState |= aData.mPermanentState | aData.mFalseState;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!aElement->AttrValueIs(kNameSpaceID_None, aData.mAttrName,
|
||||
nsGkAtoms::_undefined, eCaseMatters) &&
|
||||
!aElement->AttrValueIs(kNameSpaceID_None, aData.mAttrName,
|
||||
nsGkAtoms::_empty, eCaseMatters)) {
|
||||
*aState |= aData.mPermanentState | aData.mTrueState;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (aData.mType & eDefinedIfAbsent)
|
||||
*aState |= aData.mPermanentState | aData.mFalseState;
|
||||
}
|
62
accessible/src/base/ARIAStateMap.h
Normal file
62
accessible/src/base/ARIAStateMap.h
Normal file
@ -0,0 +1,62 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef _mozilla_a11y_aria_ARIAStateMap_h_
|
||||
#define _mozilla_a11y_aria_ARIAStateMap_h_
|
||||
|
||||
#include "prtypes.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
namespace dom {
|
||||
class Element;
|
||||
}
|
||||
|
||||
namespace a11y {
|
||||
namespace aria {
|
||||
|
||||
/**
|
||||
* List of the ARIA state mapping rules.
|
||||
*/
|
||||
enum EStateRule
|
||||
{
|
||||
eARIANone,
|
||||
eARIAAutoComplete,
|
||||
eARIABusy,
|
||||
eARIACheckableBool,
|
||||
eARIACheckableMixed,
|
||||
eARIACheckedMixed,
|
||||
eARIADisabled,
|
||||
eARIAExpanded,
|
||||
eARIAHasPopup,
|
||||
eARIAInvalid,
|
||||
eARIAMultiline,
|
||||
eARIAMultiSelectable,
|
||||
eARIAOrientation,
|
||||
eARIAPressed,
|
||||
eARIAReadonly,
|
||||
eARIAReadonlyOrEditable,
|
||||
eARIARequired,
|
||||
eARIASelectable,
|
||||
eReadonlyUntilEditable
|
||||
};
|
||||
|
||||
/**
|
||||
* Expose the accessible states for the given element accordingly to state
|
||||
* mapping rule.
|
||||
*
|
||||
* @param aRule [in] state mapping rule ID
|
||||
* @param aElement [in] node of the accessible
|
||||
* @param aState [in/out] accessible states
|
||||
* @return true if state map rule ID is valid
|
||||
*/
|
||||
bool MapToState(EStateRule aRule, dom::Element* aElement, PRUint64* aState);
|
||||
|
||||
} // namespace aria
|
||||
} // namespace a11y
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
@ -52,6 +52,7 @@ CPPSRCS = \
|
||||
AccEvent.cpp \
|
||||
AccGroupInfo.cpp \
|
||||
AccIterator.cpp \
|
||||
ARIAStateMap.cpp \
|
||||
filters.cpp \
|
||||
FocusManager.cpp \
|
||||
NotificationController.cpp \
|
||||
@ -91,6 +92,7 @@ EXPORTS = \
|
||||
EXPORTS_NAMESPACES = mozilla/a11y
|
||||
|
||||
EXPORTS_mozilla/a11y = \
|
||||
ARIAStateMap.h \
|
||||
FocusManager.h \
|
||||
States.h \
|
||||
Role.h \
|
||||
|
@ -39,20 +39,20 @@
|
||||
|
||||
#include "nsARIAMap.h"
|
||||
|
||||
#include "nsIAccessibleRole.h"
|
||||
#include "Role.h"
|
||||
#include "States.h"
|
||||
|
||||
#include "nsIContent.h"
|
||||
|
||||
using namespace mozilla::a11y;
|
||||
using namespace mozilla::a11y::aria;
|
||||
|
||||
/**
|
||||
* This list of WAI-defined roles are currently hardcoded.
|
||||
* Eventually we will most likely be loading an RDF resource that contains this information
|
||||
* Using RDF will also allow for role extensibility. See bug 280138.
|
||||
*
|
||||
* Definition of nsRoleMapEntry and nsStateMapEntry contains comments explaining this table.
|
||||
* Definition of nsRoleMapEntry contains comments explaining this table.
|
||||
*
|
||||
* When no nsIAccessibleRole enum mapping exists for an ARIA role, the
|
||||
* role will be exposed via the object attribute "xml-roles".
|
||||
@ -607,92 +607,12 @@ nsRoleMapEntry nsARIAMap::gEmptyRoleMap = {
|
||||
kNoReqStates
|
||||
};
|
||||
|
||||
nsStateMapEntry nsARIAMap::gWAIStateMap[] = {
|
||||
// eARIANone
|
||||
nsStateMapEntry(),
|
||||
|
||||
// eARIAAutoComplete
|
||||
nsStateMapEntry(&nsGkAtoms::aria_autocomplete,
|
||||
"inline", states::SUPPORTS_AUTOCOMPLETION,
|
||||
"list", states::HASPOPUP | states::SUPPORTS_AUTOCOMPLETION,
|
||||
"both", states::HASPOPUP | states::SUPPORTS_AUTOCOMPLETION),
|
||||
|
||||
// eARIABusy
|
||||
nsStateMapEntry(&nsGkAtoms::aria_busy,
|
||||
"true", states::BUSY,
|
||||
"error", states::INVALID),
|
||||
|
||||
// eARIACheckableBool
|
||||
nsStateMapEntry(&nsGkAtoms::aria_checked, kBoolType,
|
||||
states::CHECKABLE, states::CHECKED, 0, true),
|
||||
|
||||
// eARIACheckableMixed
|
||||
nsStateMapEntry(&nsGkAtoms::aria_checked, kMixedType,
|
||||
states::CHECKABLE, states::CHECKED, 0, true),
|
||||
|
||||
// eARIACheckedMixed
|
||||
nsStateMapEntry(&nsGkAtoms::aria_checked, kMixedType,
|
||||
states::CHECKABLE, states::CHECKED, 0),
|
||||
|
||||
// eARIADisabled
|
||||
nsStateMapEntry(&nsGkAtoms::aria_disabled, kBoolType,
|
||||
0, states::UNAVAILABLE),
|
||||
|
||||
// eARIAExpanded
|
||||
nsStateMapEntry(&nsGkAtoms::aria_expanded, kBoolType,
|
||||
0, states::EXPANDED, states::COLLAPSED),
|
||||
|
||||
// eARIAHasPopup
|
||||
nsStateMapEntry(&nsGkAtoms::aria_haspopup, kBoolType,
|
||||
0, states::HASPOPUP),
|
||||
|
||||
// eARIAInvalid
|
||||
nsStateMapEntry(&nsGkAtoms::aria_invalid, kBoolType,
|
||||
0, states::INVALID),
|
||||
|
||||
// eARIAMultiline
|
||||
nsStateMapEntry(&nsGkAtoms::aria_multiline, kBoolType,
|
||||
0, states::MULTI_LINE, states::SINGLE_LINE, true),
|
||||
|
||||
// eARIAMultiSelectable
|
||||
nsStateMapEntry(&nsGkAtoms::aria_multiselectable, kBoolType,
|
||||
0, states::MULTISELECTABLE | states::EXTSELECTABLE),
|
||||
|
||||
// eARIAOrientation
|
||||
nsStateMapEntry(&nsGkAtoms::aria_orientation, eUseFirstState,
|
||||
"horizontal", states::HORIZONTAL,
|
||||
"vertical", states::VERTICAL),
|
||||
|
||||
// eARIAPressed
|
||||
nsStateMapEntry(&nsGkAtoms::aria_pressed, kMixedType,
|
||||
states::CHECKABLE, states::PRESSED),
|
||||
|
||||
// eARIAReadonly
|
||||
nsStateMapEntry(&nsGkAtoms::aria_readonly, kBoolType,
|
||||
0, states::READONLY),
|
||||
|
||||
// eARIAReadonlyOrEditable
|
||||
nsStateMapEntry(&nsGkAtoms::aria_readonly, kBoolType,
|
||||
0, states::READONLY, states::EDITABLE, true),
|
||||
|
||||
// eARIARequired
|
||||
nsStateMapEntry(&nsGkAtoms::aria_required, kBoolType,
|
||||
0, states::REQUIRED),
|
||||
|
||||
// eARIASelectable
|
||||
nsStateMapEntry(&nsGkAtoms::aria_selected, kBoolType,
|
||||
states::SELECTABLE, states::SELECTED, 0, true),
|
||||
|
||||
// eReadonlyUntilEditable
|
||||
nsStateMapEntry(states::READONLY, states::EDITABLE)
|
||||
};
|
||||
|
||||
/**
|
||||
* Universal (Global) states:
|
||||
* The following state rules are applied to any accessible element,
|
||||
* whether there is an ARIA role or not:
|
||||
*/
|
||||
eStateMapEntryID nsARIAMap::gWAIUnivStateMap[] = {
|
||||
EStateRule nsARIAMap::gWAIUnivStateMap[] = {
|
||||
eARIABusy,
|
||||
eARIADisabled,
|
||||
eARIAExpanded, // Currently under spec review but precedent exists
|
||||
@ -746,182 +666,3 @@ nsAttributeCharacteristics nsARIAMap::gWAIUnivAttrMap[] = {
|
||||
};
|
||||
|
||||
PRUint32 nsARIAMap::gWAIUnivAttrMapLength = NS_ARRAY_LENGTH(nsARIAMap::gWAIUnivAttrMap);
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// nsStateMapEntry
|
||||
|
||||
nsStateMapEntry::nsStateMapEntry() :
|
||||
mAttributeName(nsnull),
|
||||
mIsToken(false),
|
||||
mPermanentState(0),
|
||||
mValue1(nsnull),
|
||||
mState1(0),
|
||||
mValue2(nsnull),
|
||||
mState2(0),
|
||||
mValue3(nsnull),
|
||||
mState3(0),
|
||||
mDefaultState(0),
|
||||
mDefinedIfAbsent(false)
|
||||
{}
|
||||
|
||||
nsStateMapEntry::nsStateMapEntry(PRUint64 aDefaultState,
|
||||
PRUint64 aExclusingState) :
|
||||
mAttributeName(nsnull),
|
||||
mIsToken(false),
|
||||
mPermanentState(0),
|
||||
mValue1(nsnull),
|
||||
mState1(0),
|
||||
mValue2(nsnull),
|
||||
mState2(0),
|
||||
mValue3(nsnull),
|
||||
mState3(0),
|
||||
mDefaultState(aDefaultState),
|
||||
mDefinedIfAbsent(false),
|
||||
mExcludingState(aExclusingState)
|
||||
{
|
||||
}
|
||||
|
||||
nsStateMapEntry::nsStateMapEntry(nsIAtom** aAttrName, eStateValueType aType,
|
||||
PRUint64 aPermanentState,
|
||||
PRUint64 aTrueState,
|
||||
PRUint64 aFalseState,
|
||||
bool aDefinedIfAbsent) :
|
||||
mAttributeName(aAttrName),
|
||||
mIsToken(true),
|
||||
mPermanentState(aPermanentState),
|
||||
mValue1("false"),
|
||||
mState1(aFalseState),
|
||||
mValue2(nsnull),
|
||||
mState2(0),
|
||||
mValue3(nsnull),
|
||||
mState3(0),
|
||||
mDefaultState(aTrueState),
|
||||
mDefinedIfAbsent(aDefinedIfAbsent),
|
||||
mExcludingState(0)
|
||||
{
|
||||
if (aType == kMixedType) {
|
||||
mValue2 = "mixed";
|
||||
mState2 = states::MIXED;
|
||||
}
|
||||
}
|
||||
|
||||
nsStateMapEntry::nsStateMapEntry(nsIAtom** aAttrName,
|
||||
const char* aValue1, PRUint64 aState1,
|
||||
const char* aValue2, PRUint64 aState2,
|
||||
const char* aValue3, PRUint64 aState3) :
|
||||
mAttributeName(aAttrName), mIsToken(false), mPermanentState(0),
|
||||
mValue1(aValue1), mState1(aState1),
|
||||
mValue2(aValue2), mState2(aState2),
|
||||
mValue3(aValue3), mState3(aState3),
|
||||
mDefaultState(0), mDefinedIfAbsent(false), mExcludingState(0)
|
||||
{
|
||||
}
|
||||
|
||||
nsStateMapEntry::nsStateMapEntry(nsIAtom** aAttrName,
|
||||
EDefaultStateRule aDefaultStateRule,
|
||||
const char* aValue1, PRUint64 aState1,
|
||||
const char* aValue2, PRUint64 aState2,
|
||||
const char* aValue3, PRUint64 aState3) :
|
||||
mAttributeName(aAttrName), mIsToken(true), mPermanentState(0),
|
||||
mValue1(aValue1), mState1(aState1),
|
||||
mValue2(aValue2), mState2(aState2),
|
||||
mValue3(aValue3), mState3(aState3),
|
||||
mDefaultState(0), mDefinedIfAbsent(true), mExcludingState(0)
|
||||
{
|
||||
if (aDefaultStateRule == eUseFirstState)
|
||||
mDefaultState = aState1;
|
||||
}
|
||||
|
||||
bool
|
||||
nsStateMapEntry::MapToStates(nsIContent* aContent, PRUint64* aState,
|
||||
eStateMapEntryID aStateMapEntryID)
|
||||
{
|
||||
// Return true if we should continue.
|
||||
if (aStateMapEntryID == eARIANone)
|
||||
return false;
|
||||
|
||||
const nsStateMapEntry& entry = nsARIAMap::gWAIStateMap[aStateMapEntryID];
|
||||
|
||||
// Non ARIA attribute case. Expose default state until excluding state is
|
||||
// presented.
|
||||
if (!entry.mAttributeName) {
|
||||
if (!(*aState & entry.mExcludingState))
|
||||
*aState |= entry.mDefaultState;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (entry.mIsToken) {
|
||||
// If attribute is considered as defined when it's absent then let's act
|
||||
// attribute value is "false" supposedly.
|
||||
bool hasAttr = aContent->HasAttr(kNameSpaceID_None, *entry.mAttributeName);
|
||||
if (entry.mDefinedIfAbsent && !hasAttr) {
|
||||
if (entry.mPermanentState)
|
||||
*aState |= entry.mPermanentState;
|
||||
if (entry.mState1)
|
||||
*aState |= entry.mState1;
|
||||
return true;
|
||||
}
|
||||
|
||||
// We only have attribute state mappings for NMTOKEN (and boolean) based
|
||||
// ARIA attributes. According to spec, a value of "undefined" is to be
|
||||
// treated equivalent to "", or the absence of the attribute. We bail out
|
||||
// for this case here.
|
||||
// Note: If this method happens to be called with a non-token based
|
||||
// attribute, for example: aria-label="" or aria-label="undefined", we will
|
||||
// bail out and not explore a state mapping, which is safe.
|
||||
if (!hasAttr ||
|
||||
aContent->AttrValueIs(kNameSpaceID_None, *entry.mAttributeName,
|
||||
nsGkAtoms::_empty, eCaseMatters) ||
|
||||
aContent->AttrValueIs(kNameSpaceID_None, *entry.mAttributeName,
|
||||
nsGkAtoms::_undefined, eCaseMatters)) {
|
||||
|
||||
if (entry.mPermanentState)
|
||||
*aState &= ~entry.mPermanentState;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (entry.mPermanentState)
|
||||
*aState |= entry.mPermanentState;
|
||||
}
|
||||
|
||||
nsAutoString attrValue;
|
||||
if (!aContent->GetAttr(kNameSpaceID_None, *entry.mAttributeName, attrValue))
|
||||
return true;
|
||||
|
||||
// Apply states for matched value. If no values was matched then apply default
|
||||
// states.
|
||||
bool applyDefaultStates = true;
|
||||
if (entry.mValue1) {
|
||||
if (attrValue.EqualsASCII(entry.mValue1)) {
|
||||
applyDefaultStates = false;
|
||||
|
||||
if (entry.mState1)
|
||||
*aState |= entry.mState1;
|
||||
} else if (entry.mValue2) {
|
||||
if (attrValue.EqualsASCII(entry.mValue2)) {
|
||||
applyDefaultStates = false;
|
||||
|
||||
if (entry.mState2)
|
||||
*aState |= entry.mState2;
|
||||
|
||||
} else if (entry.mValue3) {
|
||||
if (attrValue.EqualsASCII(entry.mValue3)) {
|
||||
applyDefaultStates = false;
|
||||
|
||||
if (entry.mState3)
|
||||
*aState |= entry.mState3;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (applyDefaultStates) {
|
||||
if (entry.mDefaultState)
|
||||
*aState |= entry.mDefaultState;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -40,6 +40,7 @@
|
||||
#ifndef _nsARIAMap_H_
|
||||
#define _nsARIAMap_H_
|
||||
|
||||
#include "mozilla/a11y/ARIAStateMap.h"
|
||||
#include "mozilla/a11y/Role.h"
|
||||
#include "prtypes.h"
|
||||
|
||||
@ -153,126 +154,12 @@ struct nsAttributeCharacteristics
|
||||
*/
|
||||
#define kNoReqStates 0
|
||||
|
||||
enum eStateValueType
|
||||
{
|
||||
kBoolType,
|
||||
kMixedType
|
||||
};
|
||||
|
||||
enum EDefaultStateRule
|
||||
{
|
||||
//eNoDefaultState,
|
||||
eUseFirstState
|
||||
};
|
||||
|
||||
/**
|
||||
* ID for state map entry, used in nsRoleMapEntry.
|
||||
*/
|
||||
enum eStateMapEntryID
|
||||
{
|
||||
eARIANone,
|
||||
eARIAAutoComplete,
|
||||
eARIABusy,
|
||||
eARIACheckableBool,
|
||||
eARIACheckableMixed,
|
||||
eARIACheckedMixed,
|
||||
eARIADisabled,
|
||||
eARIAExpanded,
|
||||
eARIAHasPopup,
|
||||
eARIAInvalid,
|
||||
eARIAMultiline,
|
||||
eARIAMultiSelectable,
|
||||
eARIAOrientation,
|
||||
eARIAPressed,
|
||||
eARIAReadonly,
|
||||
eARIAReadonlyOrEditable,
|
||||
eARIARequired,
|
||||
eARIASelectable,
|
||||
eReadonlyUntilEditable
|
||||
};
|
||||
|
||||
class nsStateMapEntry
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Used to create stub.
|
||||
*/
|
||||
nsStateMapEntry();
|
||||
|
||||
/**
|
||||
* Used to expose permanent states presented until accessible has an excluding
|
||||
* state.
|
||||
*/
|
||||
nsStateMapEntry(PRUint64 aDefaultState, PRUint64 aExclusingState);
|
||||
|
||||
/**
|
||||
* Used for ARIA attributes having boolean or mixed values.
|
||||
*/
|
||||
nsStateMapEntry(nsIAtom** aAttrName, eStateValueType aType,
|
||||
PRUint64 aPermanentState,
|
||||
PRUint64 aTrueState,
|
||||
PRUint64 aFalseState = 0,
|
||||
bool aDefinedIfAbsent = false);
|
||||
|
||||
/**
|
||||
* Used for ARIA attributes having enumerated values.
|
||||
*/
|
||||
nsStateMapEntry(nsIAtom** aAttrName,
|
||||
const char* aValue1, PRUint64 aState1,
|
||||
const char* aValue2, PRUint64 aState2,
|
||||
const char* aValue3 = 0, PRUint64 aState3 = 0);
|
||||
|
||||
/**
|
||||
* Used for ARIA attributes having enumerated values, and where a default
|
||||
* attribute state should be assumed when not supplied by the author.
|
||||
*/
|
||||
nsStateMapEntry(nsIAtom** aAttrName, EDefaultStateRule aDefaultStateRule,
|
||||
const char* aValue1, PRUint64 aState1,
|
||||
const char* aValue2, PRUint64 aState2,
|
||||
const char* aValue3 = 0, PRUint64 aState3 = 0);
|
||||
|
||||
/**
|
||||
* Maps ARIA state map pointed by state map entry ID to accessible states.
|
||||
*
|
||||
* @param aContent [in] node of the accessible
|
||||
* @param aState [in/out] accessible states
|
||||
* @param aStateMapEntryID [in] state map entry ID
|
||||
* @return true if state map entry ID is valid
|
||||
*/
|
||||
static bool MapToStates(nsIContent* aContent, PRUint64* aState,
|
||||
eStateMapEntryID aStateMapEntryID);
|
||||
|
||||
private:
|
||||
// ARIA attribute name
|
||||
nsIAtom** mAttributeName;
|
||||
|
||||
// Indicates if attribute is token (can be undefined)
|
||||
bool mIsToken;
|
||||
|
||||
// State applied always if attribute is defined
|
||||
PRUint64 mPermanentState;
|
||||
|
||||
// States applied if attribute value is matched to the stored value
|
||||
const char* mValue1;
|
||||
PRUint64 mState1;
|
||||
|
||||
const char* mValue2;
|
||||
PRUint64 mState2;
|
||||
|
||||
const char* mValue3;
|
||||
PRUint64 mState3;
|
||||
|
||||
// States applied if no stored values above are matched
|
||||
PRUint64 mDefaultState;
|
||||
|
||||
// Permanent and false states are applied if attribute is absent
|
||||
bool mDefinedIfAbsent;
|
||||
|
||||
// If this state is presented in state bits then default state is not exposed.
|
||||
PRUint64 mExcludingState;
|
||||
};
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Role map entry
|
||||
|
||||
@ -302,15 +189,15 @@ struct nsRoleMapEntry
|
||||
|
||||
// Automatic state mapping rule: always include in nsIAccessibleStates
|
||||
PRUint64 state; // or kNoReqStates if no nsIAccessibleStates are automatic for this role.
|
||||
|
||||
|
||||
// ARIA properties supported for this role
|
||||
// (in other words, the aria-foo attribute to nsIAccessibleStates mapping rules)
|
||||
// Currently you cannot have unlimited mappings, because
|
||||
// a variable sized array would not allow the use of
|
||||
// C++'s struct initialization feature.
|
||||
eStateMapEntryID attributeMap1;
|
||||
eStateMapEntryID attributeMap2;
|
||||
eStateMapEntryID attributeMap3;
|
||||
mozilla::a11y::aria::EStateRule attributeMap1;
|
||||
mozilla::a11y::aria::EStateRule attributeMap2;
|
||||
mozilla::a11y::aria::EStateRule attributeMap3;
|
||||
};
|
||||
|
||||
|
||||
@ -343,17 +230,12 @@ struct nsARIAMap
|
||||
*/
|
||||
static nsRoleMapEntry gEmptyRoleMap;
|
||||
|
||||
/**
|
||||
* State map of ARIA state attributes.
|
||||
*/
|
||||
static nsStateMapEntry gWAIStateMap[];
|
||||
|
||||
/**
|
||||
* State map of ARIA states applied to any accessible not depending on
|
||||
* the role.
|
||||
*/
|
||||
static eStateMapEntryID gWAIUnivStateMap[];
|
||||
|
||||
static mozilla::a11y::aria::EStateRule gWAIUnivStateMap[];
|
||||
|
||||
/**
|
||||
* Map of attribute to attribute characteristics.
|
||||
*/
|
||||
@ -364,11 +246,12 @@ struct nsARIAMap
|
||||
* Return accessible state from ARIA universal states applied to the given
|
||||
* element.
|
||||
*/
|
||||
static PRUint64 UniversalStatesFor(nsIContent* aContent)
|
||||
static PRUint64 UniversalStatesFor(mozilla::dom::Element* aElement)
|
||||
{
|
||||
PRUint64 state = 0;
|
||||
PRUint32 index = 0;
|
||||
while (nsStateMapEntry::MapToStates(aContent, &state, gWAIUnivStateMap[index]))
|
||||
while (mozilla::a11y::aria::MapToState(gWAIUnivStateMap[index],
|
||||
aElement, &state))
|
||||
index++;
|
||||
|
||||
return state;
|
||||
|
@ -1609,8 +1609,13 @@ nsAccessible::State()
|
||||
void
|
||||
nsAccessible::ApplyARIAState(PRUint64* aState)
|
||||
{
|
||||
if (!mContent->IsElement())
|
||||
return;
|
||||
|
||||
dom::Element* element = mContent->AsElement();
|
||||
|
||||
// Test for universal states first
|
||||
*aState |= nsARIAMap::UniversalStatesFor(mContent);
|
||||
*aState |= nsARIAMap::UniversalStatesFor(element);
|
||||
|
||||
if (mRoleMapEntry) {
|
||||
|
||||
@ -1650,16 +1655,11 @@ nsAccessible::ApplyARIAState(PRUint64* aState)
|
||||
return;
|
||||
|
||||
*aState |= mRoleMapEntry->state;
|
||||
if (nsStateMapEntry::MapToStates(mContent, aState,
|
||||
mRoleMapEntry->attributeMap1) &&
|
||||
nsStateMapEntry::MapToStates(mContent, aState,
|
||||
mRoleMapEntry->attributeMap2)) {
|
||||
nsStateMapEntry::MapToStates(mContent, aState,
|
||||
mRoleMapEntry->attributeMap3);
|
||||
}
|
||||
}
|
||||
|
||||
// Not implemented by this class
|
||||
if (aria::MapToState(mRoleMapEntry->attributeMap1, element, aState) &&
|
||||
aria::MapToState(mRoleMapEntry->attributeMap2, element, aState))
|
||||
aria::MapToState(mRoleMapEntry->attributeMap3, element, aState);
|
||||
}
|
||||
|
||||
/* DOMString getValue (); */
|
||||
NS_IMETHODIMP
|
||||
@ -2825,9 +2825,9 @@ nsAccessible::IsSelect()
|
||||
// accessible so that we can follow COM identity rules.
|
||||
|
||||
return mRoleMapEntry &&
|
||||
(mRoleMapEntry->attributeMap1 == eARIAMultiSelectable ||
|
||||
mRoleMapEntry->attributeMap2 == eARIAMultiSelectable ||
|
||||
mRoleMapEntry->attributeMap3 == eARIAMultiSelectable);
|
||||
(mRoleMapEntry->attributeMap1 == aria::eARIAMultiSelectable ||
|
||||
mRoleMapEntry->attributeMap2 == aria::eARIAMultiSelectable ||
|
||||
mRoleMapEntry->attributeMap3 == aria::eARIAMultiSelectable);
|
||||
}
|
||||
|
||||
already_AddRefed<nsIArray>
|
||||
|
@ -64,7 +64,6 @@ class nsHyperTextAccessible;
|
||||
class nsHTMLImageAccessible;
|
||||
class nsHTMLImageMapAccessible;
|
||||
class nsHTMLLIAccessible;
|
||||
struct nsRoleMapEntry;
|
||||
class Relation;
|
||||
namespace mozilla {
|
||||
namespace a11y {
|
||||
|
@ -432,7 +432,7 @@ nsHTMLTextFieldAccessible::ApplyARIAState(PRUint64* aState)
|
||||
{
|
||||
nsHyperTextAccessibleWrap::ApplyARIAState(aState);
|
||||
|
||||
nsStateMapEntry::MapToStates(mContent, aState, eARIAAutoComplete);
|
||||
aria::MapToState(aria::eARIAAutoComplete, mContent->AsElement(), aState);
|
||||
}
|
||||
|
||||
PRUint64
|
||||
|
@ -754,7 +754,7 @@ nsXULTextFieldAccessible::ApplyARIAState(PRUint64* aState)
|
||||
{
|
||||
nsHyperTextAccessibleWrap::ApplyARIAState(aState);
|
||||
|
||||
nsStateMapEntry::MapToStates(mContent, aState, eARIAAutoComplete);
|
||||
aria::MapToState(aria::eARIAAutoComplete, mContent->AsElement(), aState);
|
||||
|
||||
}
|
||||
|
||||
|
@ -2037,6 +2037,7 @@ GK_ATOM(datatable, "datatable")
|
||||
GK_ATOM(droppable, "droppable")
|
||||
GK_ATOM(eventFromInput, "event-from-input")
|
||||
GK_ATOM(InlineBlockFrame, "InlineBlockFrame")
|
||||
GK_ATOM(inlinevalue, "inline")
|
||||
GK_ATOM(invalid, "invalid")
|
||||
GK_ATOM(item, "item")
|
||||
GK_ATOM(itemset, "itemset")
|
||||
|
Loading…
x
Reference in New Issue
Block a user