Bug 741398 - make ARIA state map extensible, r=tbsaunde
authorAlexander Surkov <surkov.alexander@gmail.com>
Fri, 06 Apr 2012 01:23:30 +0900
changeset 94399 fc2d53ab4582a60d486a9258e9cade45d0b1930b
parent 94398 5738f35ffb113d6ea2ef39f30709e855c6dc38a8
child 94400 118c07dc56f993c3e0d221342d80641bb37552f1
push id886
push userlsblakk@mozilla.com
push dateMon, 04 Jun 2012 19:57:52 +0000
treeherdermozilla-beta@bbd8d5efd6d1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstbsaunde
bugs741398
milestone14.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 741398 - make ARIA state map extensible, r=tbsaunde
accessible/src/base/ARIAStateMap.cpp
accessible/src/base/ARIAStateMap.h
accessible/src/base/Makefile.in
accessible/src/base/nsARIAMap.cpp
accessible/src/base/nsARIAMap.h
accessible/src/base/nsAccessible.cpp
accessible/src/base/nsAccessible.h
accessible/src/html/nsHTMLFormControlAccessible.cpp
accessible/src/xul/nsXULFormControlAccessible.cpp
content/base/src/nsGkAtomList.h
new file mode 100644
--- /dev/null
+++ b/accessible/src/base/ARIAStateMap.cpp
@@ -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;
+}
new file mode 100644
--- /dev/null
+++ b/accessible/src/base/ARIAStateMap.h
@@ -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
--- a/accessible/src/base/Makefile.in
+++ b/accessible/src/base/Makefile.in
@@ -47,16 +47,17 @@ LIBRARY_NAME = accessibility_base_s
 LIBXUL_LIBRARY = 1
 
 
 CPPSRCS = \
   AccCollector.cpp \
   AccEvent.cpp \
   AccGroupInfo.cpp \
   AccIterator.cpp \
+  ARIAStateMap.cpp \
   filters.cpp \
   FocusManager.cpp \
   NotificationController.cpp \
   nsAccDocManager.cpp \
   nsAccessNode.cpp \
   nsARIAGridAccessible.cpp \
   nsARIAMap.cpp \
   nsDocAccessible.cpp \
@@ -86,16 +87,17 @@ EXPORTS = \
   nsAccessible.h \
   nsAccessNode.h \
   nsARIAMap.h \
   $(NULL)
 
 EXPORTS_NAMESPACES = mozilla/a11y
 
 EXPORTS_mozilla/a11y = \
+  ARIAStateMap.h \
   FocusManager.h \
   States.h \
   Role.h \
   $(NULL)
 
 # we don't want the shared lib, but we want to force the creation of a static lib.
 FORCE_STATIC_LIB = 1
 
--- a/accessible/src/base/nsARIAMap.cpp
+++ b/accessible/src/base/nsARIAMap.cpp
@@ -34,30 +34,30 @@
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #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".
  *  In addition, in MSAA, the unmapped role will also be exposed as a BSTR string role.
  *
  *  There are no nsIAccessibleRole enums for the following landmark roles:
  *    banner, contentinfo, main, navigation, note, search, secondary, seealso, breadcrumbs
  */
@@ -602,102 +602,22 @@ nsRoleMapEntry nsARIAMap::gEmptyRoleMap 
   roles::NOTHING,
   kUseMapRole,
   eNoValue,
   eNoAction,
   eNoLiveAttr,
   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
   eARIAHasPopup,  // Note this is technically a "property"
   eARIAInvalid,
   eARIARequired,  // XXX not global, Bug 553117
   eARIANone
 };
@@ -741,187 +661,8 @@ nsAttributeCharacteristics nsARIAMap::gW
   {&nsGkAtoms::aria_sort,                               ATTR_VALTOKEN },
   {&nsGkAtoms::aria_valuenow,          ATTR_BYPASSOBJ                 },
   {&nsGkAtoms::aria_valuemin,          ATTR_BYPASSOBJ                 },
   {&nsGkAtoms::aria_valuemax,          ATTR_BYPASSOBJ                 },
   {&nsGkAtoms::aria_valuetext,         ATTR_BYPASSOBJ                 }
 };
 
 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;
-}
--- a/accessible/src/base/nsARIAMap.h
+++ b/accessible/src/base/nsARIAMap.h
@@ -35,16 +35,17 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef _nsARIAMap_H_
 #define _nsARIAMap_H_
 
+#include "mozilla/a11y/ARIAStateMap.h"
 #include "mozilla/a11y/Role.h"
 #include "prtypes.h"
 
 class nsIAtom;
 class nsIContent;
 
 ////////////////////////////////////////////////////////////////////////////////
 // Value constants
@@ -148,136 +149,22 @@ struct nsAttributeCharacteristics
 // State map entry
 
 /**
  * Used in nsRoleMapEntry.state if no nsIAccessibleStates are automatic for
  * a given role.
  */
 #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
 
 /**
  * For each ARIA role, this maps the nsIAccessible information.
  */
 struct nsRoleMapEntry
 {
@@ -297,25 +184,25 @@ struct nsRoleMapEntry
   EActionRule actionRule;
 
   // 'live' and 'container-live' object attributes mapping rule: how to expose
   // these object attributes if ARIA 'live' attribute is missed.
   ELiveAttrRule liveAttRule;
 
   // 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;
 };
 
 
 ////////////////////////////////////////////////////////////////////////////////
 // ARIA map
 
 /**
  *  These are currently initialized (hardcoded) in nsARIAMap.cpp, 
@@ -339,40 +226,36 @@ struct nsARIAMap
   /**
    * Empty role map entry. Used by accessibility service to create an accessible
    * if the accessible can't use role of used accessible class. For example,
    * it is used for table cells that aren't contained by table.
    */
   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.
    */
   static nsAttributeCharacteristics gWAIUnivAttrMap[];
   static PRUint32 gWAIUnivAttrMapLength;
 
   /**
    * 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;
   }
 };
 
 #endif
--- a/accessible/src/base/nsAccessible.cpp
+++ b/accessible/src/base/nsAccessible.cpp
@@ -1604,18 +1604,23 @@ nsAccessible::State()
   }
 
   return 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) {
 
     // We only force the readonly bit off if we have a real mapping for the aria
     // role. This preserves the ability for screen readers to use readonly
     // (primarily on the document) as the hint for creating a virtual buffer.
     if (mRoleMapEntry->role != roles::NOTHING)
       *aState &= ~states::READONLY;
@@ -1645,27 +1650,22 @@ nsAccessible::ApplyARIAState(PRUint64* a
       }
     }    
   }
 
   if (!mRoleMapEntry)
     return;
 
   *aState |= mRoleMapEntry->state;
-  if (nsStateMapEntry::MapToStates(mContent, aState,
-                                   mRoleMapEntry->attributeMap1) &&
-      nsStateMapEntry::MapToStates(mContent, aState,
-                                   mRoleMapEntry->attributeMap2)) {
-    nsStateMapEntry::MapToStates(mContent, aState,
-                                 mRoleMapEntry->attributeMap3);
-  }
+
+  if (aria::MapToState(mRoleMapEntry->attributeMap1, element, aState) &&
+      aria::MapToState(mRoleMapEntry->attributeMap2, element, aState))
+    aria::MapToState(mRoleMapEntry->attributeMap3, element, aState);
 }
 
-// Not implemented by this class
-
 /* DOMString getValue (); */
 NS_IMETHODIMP
 nsAccessible::GetValue(nsAString& aValue)
 {
   if (IsDefunct())
     return NS_ERROR_FAILURE;
 
   if (mRoleMapEntry) {
@@ -2820,19 +2820,19 @@ bool
 nsAccessible::IsSelect()
 {
   // If we have an ARIA role attribute present and the role allows multi
   // selectable state, then we need to support SelectAccessible interface. If
   // either attribute (role or multiselectable) change, then we'll destroy this
   // 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>
 nsAccessible::SelectedItems()
 {
   nsCOMPtr<nsIMutableArray> selectedItems = do_CreateInstance(NS_ARRAY_CONTRACTID);
   if (!selectedItems)
     return nsnull;
--- a/accessible/src/base/nsAccessible.h
+++ b/accessible/src/base/nsAccessible.h
@@ -59,17 +59,16 @@ class AccEvent;
 class AccGroupInfo;
 class EmbeddedObjCollector;
 class KeyBinding;
 class nsAccessible;
 class nsHyperTextAccessible;
 class nsHTMLImageAccessible;
 class nsHTMLImageMapAccessible;
 class nsHTMLLIAccessible;
-struct nsRoleMapEntry;
 class Relation;
 namespace mozilla {
 namespace a11y {
 class TableAccessible;
 }
 }
 class nsTextAccessible;
 class nsXULTreeAccessible;
--- a/accessible/src/html/nsHTMLFormControlAccessible.cpp
+++ b/accessible/src/html/nsHTMLFormControlAccessible.cpp
@@ -427,17 +427,17 @@ NS_IMETHODIMP nsHTMLTextFieldAccessible:
   return NS_ERROR_FAILURE;
 }
 
 void
 nsHTMLTextFieldAccessible::ApplyARIAState(PRUint64* aState)
 {
   nsHyperTextAccessibleWrap::ApplyARIAState(aState);
 
-  nsStateMapEntry::MapToStates(mContent, aState, eARIAAutoComplete);
+  aria::MapToState(aria::eARIAAutoComplete, mContent->AsElement(), aState);
 }
 
 PRUint64
 nsHTMLTextFieldAccessible::State()
 {
   PRUint64 state = nsHyperTextAccessibleWrap::State();
   if (state & states::DEFUNCT)
     return state;
--- a/accessible/src/xul/nsXULFormControlAccessible.cpp
+++ b/accessible/src/xul/nsXULFormControlAccessible.cpp
@@ -749,17 +749,17 @@ NS_IMETHODIMP nsXULTextFieldAccessible::
   return NS_ERROR_FAILURE;
 }
 
 void
 nsXULTextFieldAccessible::ApplyARIAState(PRUint64* aState)
 {
   nsHyperTextAccessibleWrap::ApplyARIAState(aState);
 
-  nsStateMapEntry::MapToStates(mContent, aState, eARIAAutoComplete);
+  aria::MapToState(aria::eARIAAutoComplete, mContent->AsElement(), aState);
 
 }
 
 PRUint64
 nsXULTextFieldAccessible::NativeState()
 {
   PRUint64 state = nsHyperTextAccessibleWrap::NativeState();
 
--- a/content/base/src/nsGkAtomList.h
+++ b/content/base/src/nsGkAtomList.h
@@ -2032,16 +2032,17 @@ GK_ATOM(containerBusy, "container-busy")
 GK_ATOM(containerLive, "container-live")
 GK_ATOM(containerLiveRole, "container-live-role")
 GK_ATOM(containerRelevant, "container-relevant")
 GK_ATOM(cycles, "cycles")
 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")
 GK_ATOM(lineNumber, "line-number")
 GK_ATOM(linkedPanel, "linkedpanel")
 GK_ATOM(live, "live")
 GK_ATOM(marginBottom, "margin-bottom")
 GK_ATOM(marginLeft, "margin-left")