Bug 523068 - group attributes should be calculated from groupPosition(), r=marcoz, davidb
authorAlexander Surkov <surkov.alexander@gmail.com>
Wed, 06 Jan 2010 18:36:50 +0800
changeset 36879 3202d6d22192ce7036ca746d47e3a0dd177d635e
parent 36878 880125b33bca6a91a14fec1e3a651b5fde0c194a
child 36880 176a4e20089ec7eaaf5d1d76a5f5e24fd62c30d8
push id11035
push usersurkov.alexander@gmail.com
push dateWed, 06 Jan 2010 10:42:50 +0000
treeherdermozilla-central@3202d6d22192 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmarcoz, davidb
bugs523068
milestone1.9.3a1pre
Bug 523068 - group attributes should be calculated from groupPosition(), r=marcoz, davidb
accessible/src/base/nsARIAMap.cpp
accessible/src/base/nsAccUtils.cpp
accessible/src/base/nsAccUtils.h
accessible/src/base/nsAccessible.cpp
accessible/src/base/nsAccessible.h
accessible/src/html/nsHTMLFormControlAccessible.cpp
accessible/src/html/nsHTMLFormControlAccessible.h
accessible/src/html/nsHTMLSelectAccessible.cpp
accessible/src/html/nsHTMLSelectAccessible.h
accessible/src/html/nsHyperTextAccessible.cpp
accessible/src/html/nsHyperTextAccessible.h
accessible/src/msaa/nsAccessibleWrap.cpp
accessible/src/xul/nsXULFormControlAccessible.cpp
accessible/src/xul/nsXULFormControlAccessible.h
accessible/src/xul/nsXULListboxAccessible.cpp
accessible/src/xul/nsXULListboxAccessible.h
accessible/src/xul/nsXULMenuAccessible.cpp
accessible/src/xul/nsXULMenuAccessible.h
accessible/src/xul/nsXULTabAccessible.cpp
accessible/src/xul/nsXULTabAccessible.h
accessible/src/xul/nsXULTreeAccessible.cpp
accessible/src/xul/nsXULTreeAccessible.h
accessible/tests/mochitest/attributes.js
accessible/tests/mochitest/attributes/test_obj_group.html
accessible/tests/mochitest/attributes/test_obj_group.xul
accessible/tests/mochitest/attributes/test_obj_group_tree.xul
--- a/accessible/src/base/nsARIAMap.cpp
+++ b/accessible/src/base/nsARIAMap.cpp
@@ -700,26 +700,29 @@ nsAttributeCharacteristics nsARIAMap::gW
   {&nsAccessibilityAtoms::aria_disabled,          ATTR_BYPASSOBJ | ATTR_VALTOKEN },
   {&nsAccessibilityAtoms::aria_dropeffect,                         ATTR_VALTOKEN },
   {&nsAccessibilityAtoms::aria_expanded,          ATTR_BYPASSOBJ | ATTR_VALTOKEN },
   {&nsAccessibilityAtoms::aria_flowto,            ATTR_BYPASSOBJ                 },  
   {&nsAccessibilityAtoms::aria_grabbed,                            ATTR_VALTOKEN },
   {&nsAccessibilityAtoms::aria_haspopup,          ATTR_BYPASSOBJ | ATTR_VALTOKEN },
   {&nsAccessibilityAtoms::aria_invalid,           ATTR_BYPASSOBJ | ATTR_VALTOKEN },
   {&nsAccessibilityAtoms::aria_labelledby,        ATTR_BYPASSOBJ                 },
+  {&nsAccessibilityAtoms::aria_level,             ATTR_BYPASSOBJ                 }, /* handled via groupPosition */
   {&nsAccessibilityAtoms::aria_live,                               ATTR_VALTOKEN },
   {&nsAccessibilityAtoms::aria_multiline,         ATTR_BYPASSOBJ | ATTR_VALTOKEN },
   {&nsAccessibilityAtoms::aria_multiselectable,   ATTR_BYPASSOBJ | ATTR_VALTOKEN },
   {&nsAccessibilityAtoms::aria_owns,              ATTR_BYPASSOBJ                 },
   {&nsAccessibilityAtoms::aria_orientation,                        ATTR_VALTOKEN },
+  {&nsAccessibilityAtoms::aria_posinset,          ATTR_BYPASSOBJ                 }, /* handled via groupPosition */
   {&nsAccessibilityAtoms::aria_pressed,           ATTR_BYPASSOBJ | ATTR_VALTOKEN },
   {&nsAccessibilityAtoms::aria_readonly,          ATTR_BYPASSOBJ | ATTR_VALTOKEN },
   {&nsAccessibilityAtoms::aria_relevant,          ATTR_BYPASSOBJ                 },
   {&nsAccessibilityAtoms::aria_required,          ATTR_BYPASSOBJ | ATTR_VALTOKEN },
   {&nsAccessibilityAtoms::aria_selected,          ATTR_BYPASSOBJ | ATTR_VALTOKEN },
+  {&nsAccessibilityAtoms::aria_setsize,           ATTR_BYPASSOBJ                 }, /* handled via groupPosition */
   {&nsAccessibilityAtoms::aria_sort,                               ATTR_VALTOKEN },
   {&nsAccessibilityAtoms::aria_valuenow,          ATTR_BYPASSOBJ                 },
   {&nsAccessibilityAtoms::aria_valuemin,          ATTR_BYPASSOBJ                 },
   {&nsAccessibilityAtoms::aria_valuemax,          ATTR_BYPASSOBJ                 },
   {&nsAccessibilityAtoms::aria_valuetext,         ATTR_BYPASSOBJ                 }
 };
 
 PRUint32 nsARIAMap::gWAIUnivAttrMapLength = NS_ARRAY_LENGTH(nsARIAMap::gWAIUnivAttrMap);
--- a/accessible/src/base/nsAccUtils.cpp
+++ b/accessible/src/base/nsAccUtils.cpp
@@ -76,67 +76,19 @@ nsAccUtils::SetAccAttr(nsIPersistentProp
   nsAutoString oldValue;
   nsCAutoString attrName;
 
   aAttrName->ToUTF8String(attrName);
   aAttributes->SetStringProperty(attrName, aAttrValue, oldValue);
 }
 
 void
-nsAccUtils::GetAccGroupAttrs(nsIPersistentProperties *aAttributes,
-                             PRInt32 *aLevel, PRInt32 *aPosInSet,
-                             PRInt32 *aSetSize)
-{
-  *aLevel = 0;
-  *aPosInSet = 0;
-  *aSetSize = 0;
-
-  nsAutoString value;
-  PRInt32 error = NS_OK;
-
-  GetAccAttr(aAttributes, nsAccessibilityAtoms::level, value);
-  if (!value.IsEmpty()) {
-    PRInt32 level = value.ToInteger(&error);
-    if (NS_SUCCEEDED(error))
-      *aLevel = level;
-  }
-
-  GetAccAttr(aAttributes, nsAccessibilityAtoms::posinset, value);
-  if (!value.IsEmpty()) {
-    PRInt32 posInSet = value.ToInteger(&error);
-    if (NS_SUCCEEDED(error))
-      *aPosInSet = posInSet;
-  }
-
-  GetAccAttr(aAttributes, nsAccessibilityAtoms::setsize, value);
-  if (!value.IsEmpty()) {
-    PRInt32 sizeSet = value.ToInteger(&error);
-    if (NS_SUCCEEDED(error))
-      *aSetSize = sizeSet;
-  }
-}
-
-PRBool
-nsAccUtils::HasAccGroupAttrs(nsIPersistentProperties *aAttributes)
-{
-  nsAutoString value;
-
-  GetAccAttr(aAttributes, nsAccessibilityAtoms::setsize, value);
-  if (!value.IsEmpty()) {
-    GetAccAttr(aAttributes, nsAccessibilityAtoms::posinset, value);
-    return !value.IsEmpty();
-  }
-
-  return PR_FALSE;
-}
-
-void
 nsAccUtils::SetAccGroupAttrs(nsIPersistentProperties *aAttributes,
-                             PRInt32 aLevel, PRInt32 aPosInSet,
-                             PRInt32 aSetSize)
+                             PRInt32 aLevel, PRInt32 aSetSize,
+                             PRInt32 aPosInSet)
 {
   nsAutoString value;
 
   if (aLevel) {
     value.AppendInt(aLevel);
     SetAccAttr(aAttributes, nsAccessibilityAtoms::level, value);
   }
 
@@ -147,57 +99,61 @@ nsAccUtils::SetAccGroupAttrs(nsIPersiste
 
     value.Truncate();
     value.AppendInt(aSetSize);
     SetAccAttr(aAttributes, nsAccessibilityAtoms::setsize, value);
   }
 }
 
 void
-nsAccUtils::SetAccAttrsForXULSelectControlItem(nsIDOMNode *aNode,
-                                               nsIPersistentProperties *aAttributes)
+nsAccUtils::GetPositionAndSizeForXULSelectControlItem(nsIDOMNode *aNode,
+                                                      PRInt32 *aPosInSet,
+                                                      PRInt32 *aSetSize)
 {
   nsCOMPtr<nsIDOMXULSelectControlItemElement> item(do_QueryInterface(aNode));
   if (!item)
     return;
 
   nsCOMPtr<nsIDOMXULSelectControlElement> control;
   item->GetControl(getter_AddRefs(control));
   if (!control)
     return;
 
   PRUint32 itemsCount = 0;
   control->GetItemCount(&itemsCount);
 
   PRInt32 indexOf = 0;
   control->GetIndexOfItem(item, &indexOf);
 
-  PRUint32 setSize = itemsCount, posInSet = indexOf;
+  *aSetSize = itemsCount;
+  *aPosInSet = indexOf;
+
   for (PRUint32 index = 0; index < itemsCount; index++) {
     nsCOMPtr<nsIDOMXULSelectControlItemElement> currItem;
     control->GetItemAtIndex(index, getter_AddRefs(currItem));
     nsCOMPtr<nsIDOMNode> currNode(do_QueryInterface(currItem));
 
     nsCOMPtr<nsIAccessible> itemAcc;
     nsAccessNode::GetAccService()->GetAccessibleFor(currNode,
                                                     getter_AddRefs(itemAcc));
     if (!itemAcc ||
         State(itemAcc) & nsIAccessibleStates::STATE_INVISIBLE) {
-      setSize--;
+      (*aSetSize)--;
       if (index < static_cast<PRUint32>(indexOf))
-        posInSet--;
+        (*aPosInSet)--;
     }
   }
 
-  SetAccGroupAttrs(aAttributes, 0, posInSet + 1, setSize);
+  (*aPosInSet)++; // group position is 1-index based.
 }
 
 void
-nsAccUtils::SetAccAttrsForXULContainerItem(nsIDOMNode *aNode,
-                                           nsIPersistentProperties *aAttributes)
+nsAccUtils::GetPositionAndSizeForXULContainerItem(nsIDOMNode *aNode,
+                                                  PRInt32 *aPosInSet,
+                                                  PRInt32 *aSetSize)
 {
   nsCOMPtr<nsIDOMXULContainerItemElement> item(do_QueryInterface(aNode));
   if (!item)
     return;
 
   nsCOMPtr<nsIDOMXULContainerElement> container;
   item->GetParentContainer(getter_AddRefs(container));
   if (!container)
@@ -207,34 +163,34 @@ nsAccUtils::SetAccAttrsForXULContainerIt
   PRUint32 itemsCount = 0;
   container->GetItemCount(&itemsCount);
 
   // Get item index.
   PRInt32 indexOf = 0;
   container->GetIndexOfItem(item, &indexOf);
 
   // Calculate set size and position in the set.
-  PRUint32 setSize = 0, posInSet = 0;
+  *aSetSize = 0, *aPosInSet = 0;
   for (PRInt32 index = indexOf; index >= 0; index--) {
     nsCOMPtr<nsIDOMXULElement> item;
     container->GetItemAtIndex(index, getter_AddRefs(item));
 
     nsCOMPtr<nsIAccessible> itemAcc;
     nsAccessNode::GetAccService()->GetAccessibleFor(item,
                                                     getter_AddRefs(itemAcc));
 
     if (itemAcc) {
       PRUint32 itemRole = Role(itemAcc);
       if (itemRole == nsIAccessibleRole::ROLE_SEPARATOR)
         break; // We reached the beginning of our group.
 
       PRUint32 itemState = State(itemAcc);
       if (!(itemState & nsIAccessibleStates::STATE_INVISIBLE)) {
-        setSize++;
-        posInSet++;
+        (*aSetSize)++;
+        (*aPosInSet)++;
       }
     }
   }
 
   for (PRInt32 index = indexOf + 1; index < static_cast<PRInt32>(itemsCount);
        index++) {
     nsCOMPtr<nsIDOMXULElement> item;
     container->GetItemAtIndex(index, getter_AddRefs(item));
@@ -245,31 +201,44 @@ nsAccUtils::SetAccAttrsForXULContainerIt
 
     if (itemAcc) {
       PRUint32 itemRole = Role(itemAcc);
       if (itemRole == nsIAccessibleRole::ROLE_SEPARATOR)
         break; // We reached the end of our group.
 
       PRUint32 itemState = State(itemAcc);
       if (!(itemState & nsIAccessibleStates::STATE_INVISIBLE))
-        setSize++;
+        (*aSetSize)++;
     }
   }
+}
+
+PRInt32
+nsAccUtils::GetLevelForXULContainerItem(nsIDOMNode *aNode)
+{
+  nsCOMPtr<nsIDOMXULContainerItemElement> item(do_QueryInterface(aNode));
+  if (!item)
+    return 0;
+
+  nsCOMPtr<nsIDOMXULContainerElement> container;
+  item->GetParentContainer(getter_AddRefs(container));
+  if (!container)
+    return 0;
 
   // Get level of the item.
   PRInt32 level = -1;
   while (container) {
     level++;
 
     nsCOMPtr<nsIDOMXULContainerElement> parentContainer;
     container->GetParentContainer(getter_AddRefs(parentContainer));
     parentContainer.swap(container);
   }
-  
-  SetAccGroupAttrs(aAttributes, level, posInSet, setSize);
+
+  return level;
 }
 
 void
 nsAccUtils::SetLiveContainerAttributes(nsIPersistentProperties *aAttributes,
                                        nsIContent *aStartContent,
                                        nsIContent *aTopContent)
 {
   nsAutoString atomic, live, relevant, busy;
--- a/accessible/src/base/nsAccUtils.h
+++ b/accessible/src/base/nsAccUtils.h
@@ -81,55 +81,42 @@ public:
    * @param aAttrName - the name of requested attribute
    * @param aAttrValue - new value of attribute
    */
   static void SetAccAttr(nsIPersistentProperties *aAttributes,
                          nsIAtom *aAttrName,
                          const nsAString& aAttrValue);
 
   /**
-   * Return values of group attributes ('level', 'setsize', 'posinset')
-   */
-  static void GetAccGroupAttrs(nsIPersistentProperties *aAttributes,
-                               PRInt32 *aLevel,
-                               PRInt32 *aPosInSet,
-                               PRInt32 *aSetSize);
-
-  /**
-   * Returns true if there are level, posinset and sizeset attributes.
-   */
-  static PRBool HasAccGroupAttrs(nsIPersistentProperties *aAttributes);
-
-  /**
    * Set group attributes ('level', 'setsize', 'posinset').
    */
   static void SetAccGroupAttrs(nsIPersistentProperties *aAttributes,
-                               PRInt32 aLevel,
-                               PRInt32 aPosInSet,
-                               PRInt32 aSetSize);
+                               PRInt32 aLevel, PRInt32 aSetSize,
+                               PRInt32 aPosInSet);
+
+  /**
+   * Compute position in group (posinset) and group size (setsize) for
+   * nsIDOMXULSelectControlItemElement node.
+   */
+  static void GetPositionAndSizeForXULSelectControlItem(nsIDOMNode *aNode,
+                                                        PRInt32 *aPosInSet,
+                                                        PRInt32 *aSetSize);
 
   /**
-   * Set group attributes - 'level', 'setsize', 'posinset'.
-   *
-   * @param aNode - XUL element that implements
-   *                nsIDOMXULSelectControlItemElement interface
-   * @param aAttributes - attributes container
+   * Compute group position and group size (posinset and setsize) for
+   * nsIDOMXULContainerItemElement node.
    */
-  static void SetAccAttrsForXULSelectControlItem(nsIDOMNode *aNode,
-                                                 nsIPersistentProperties *aAttributes);
+  static void GetPositionAndSizeForXULContainerItem(nsIDOMNode *aNode,
+                                                    PRInt32 *aPosInSet,
+                                                    PRInt32 *aSetSize);
 
   /**
-   * Set group attributes - 'level', 'setsize', 'posinset'.
-   *
-   * @param  aNode        XUL element that implements
-   *                      nsIDOMXULContainerItemElement interface
-   * @param  aAttributes  attributes container
+   * Compute group level for nsIDOMXULContainerItemElement node.
    */
-  static void SetAccAttrsForXULContainerItem(nsIDOMNode *aNode,
-                                             nsIPersistentProperties *aAttributes);
+  static PRInt32 GetLevelForXULContainerItem(nsIDOMNode *aNode);
 
   /**
    * Set container-foo live region attributes for the given node.
    *
    * @param aAttributes    where to store the attributes
    * @param aStartContent  node to start from
    * @param aTopContent    node to end at
    */
--- a/accessible/src/base/nsAccessible.cpp
+++ b/accessible/src/base/nsAccessible.cpp
@@ -1501,23 +1501,20 @@ nsAccessible::GetAttributes(nsIPersisten
     attributes->SetStringProperty(NS_LITERAL_CSTRING("valuetext"), valuetext, oldValueUnused);
   }
 
   // Expose checkable object attribute if the accessible has checkable state
   if (nsAccUtils::State(this) & nsIAccessibleStates::STATE_CHECKABLE)
     nsAccUtils::SetAccAttr(attributes, nsAccessibilityAtoms::checkable, NS_LITERAL_STRING("true"));
 
   // Group attributes (level/setsize/posinset)
-  if (!nsAccUtils::HasAccGroupAttrs(attributes)) {
-    // Calculate group attributes based on accessible hierarhy if they weren't
-    // provided by ARIA or by accessible class implementation.
-    PRUint32 role = nsAccUtils::Role(this);
-    rv = ComputeGroupAttributes(role, attributes);
-    NS_ENSURE_SUCCESS(rv, rv);
-  }
+  PRInt32 level = 0, posInSet = 0, setSize = 0;
+  rv = GroupPosition(&level, &setSize, &posInSet);
+  if (NS_SUCCEEDED(rv))
+    nsAccUtils::SetAccGroupAttrs(attributes, level, setSize, posInSet);
 
   // Expose object attributes from ARIA attributes.
   PRUint32 numAttrs = content->GetAttrCount();
   for (PRUint32 count = 0; count < numAttrs; count ++) {
     const nsAttrName *attr = content->GetAttrNameAt(count);
     if (attr && attr->NamespaceEquals(kNameSpaceID_None)) {
       nsIAtom *attrAtom = attr->Atom();
       const char *attrStr;
@@ -1650,47 +1647,81 @@ nsAccessible::GetAttributesInternal(nsIP
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsAccessible::GroupPosition(PRInt32 *aGroupLevel,
                             PRInt32 *aSimilarItemsInGroup,
                             PRInt32 *aPositionInGroup)
 {
-  // Every element exposes level/posinset/sizeset for IAccessdible::attributes
-  // if they make sense for it. These attributes are mapped into groupPosition.
-  // If 'level' attribute doesn't make sense element then it isn't represented
-  // via IAccessible::attributes and groupLevel of groupPosition method is 0.
-  // Elements that expose 'level' attribute only (like html headings elements)
-  // don't support this method and all arguments  are equalled 0.
-
   NS_ENSURE_ARG_POINTER(aGroupLevel);
+  *aGroupLevel = 0;
+
   NS_ENSURE_ARG_POINTER(aSimilarItemsInGroup);
+  *aSimilarItemsInGroup = 0;
+
   NS_ENSURE_ARG_POINTER(aPositionInGroup);
-
-  *aGroupLevel = 0;
-  *aSimilarItemsInGroup = 0;
   *aPositionInGroup = 0;
 
-  nsCOMPtr<nsIPersistentProperties> attributes;
-  nsresult rv = GetAttributes(getter_AddRefs(attributes));
-  NS_ENSURE_SUCCESS(rv, rv);
-  if (!attributes) {
+  if (IsDefunct())
     return NS_ERROR_FAILURE;
+
+  // Get group position from ARIA attributes.
+  nsCOMPtr<nsIContent> content = nsCoreUtils::GetRoleContent(mDOMNode);
+  if (!content)
+    return NS_OK;
+
+  nsAutoString value;
+  PRInt32 error = NS_OK;
+
+  content->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::aria_level, value);
+  if (!value.IsEmpty()) {
+    PRInt32 level = value.ToInteger(&error);
+    if (NS_SUCCEEDED(error))
+      *aGroupLevel = level;
+  }
+
+  content->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::aria_posinset, value);
+  if (!value.IsEmpty()) {
+    PRInt32 posInSet = value.ToInteger(&error);
+    if (NS_SUCCEEDED(error))
+      *aPositionInGroup = posInSet;
   }
-  PRInt32 level, posInSet, setSize;
-  nsAccUtils::GetAccGroupAttrs(attributes, &level, &posInSet, &setSize);
-
-  if (!posInSet && !setSize)
+
+  content->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::aria_setsize, value);
+  if (!value.IsEmpty()) {
+    PRInt32 sizeSet = value.ToInteger(&error);
+    if (NS_SUCCEEDED(error))
+      *aSimilarItemsInGroup = sizeSet;
+  }
+
+  // If ARIA is missed and the accessible is visible then calculate group
+  // position from hierarchy.
+  if (nsAccUtils::State(this) & nsIAccessibleStates::STATE_INVISIBLE)
     return NS_OK;
 
-  *aGroupLevel = level;
-
-  *aPositionInGroup = posInSet;
-  *aSimilarItemsInGroup = setSize;
+  // Calculate group level if ARIA is missed.
+  if (*aGroupLevel == 0) {
+    PRInt32 level = GetLevelInternal();
+    if (level != 0)
+      *aGroupLevel = level;
+  }
+
+  // Calculate position in group and group size if ARIA is missed.
+  if (*aSimilarItemsInGroup == 0 || *aPositionInGroup == 0) {
+    PRInt32 posInSet = 0, setSize = 0;
+    GetPositionAndSizeInternal(&posInSet, &setSize);
+    if (posInSet != 0 && setSize != 0) {
+      if (*aPositionInGroup == 0)
+        *aPositionInGroup = posInSet;
+
+      if (*aSimilarItemsInGroup == 0)
+        *aSimilarItemsInGroup = setSize;
+    }
+  }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsAccessible::GetState(PRUint32 *aState, PRUint32 *aExtraState)
 {
   NS_ENSURE_ARG_POINTER(aState);
@@ -3286,58 +3317,47 @@ nsAccessible::GetActionRule(PRUint32 aSt
   // Get an action based on ARIA attribute.
   if (nsAccUtils::HasDefinedARIAToken(content,
                                    nsAccessibilityAtoms::aria_expanded))
     return eExpandAction;
 
   return eNoAction;
 }
 
-nsresult
-nsAccessible::ComputeGroupAttributes(PRUint32 aRole,
-                                     nsIPersistentProperties *aAttributes)
+void
+nsAccessible::GetPositionAndSizeInternal(PRInt32 *aPosInSet, PRInt32 *aSetSize)
 {
-  // The role of an accessible can be specified by ARIA attribute but ARIA
-  // posinset, level, setsize may be skipped. As well this method is used
-  // for non ARIA accessibles to avoid GetAccessibleInternal() method
-  // implementation in subclasses. For example, it's being used to calculate
-  // group attributes for HTML li elements.
-
-  // If accessible is invisible we don't want to calculate group attributes for
-  // it.
-  if (nsAccUtils::State(this) & nsIAccessibleStates::STATE_INVISIBLE)
-    return NS_OK;
-
-  if (aRole != nsIAccessibleRole::ROLE_LISTITEM &&
-      aRole != nsIAccessibleRole::ROLE_MENUITEM &&
-      aRole != nsIAccessibleRole::ROLE_CHECK_MENU_ITEM &&
-      aRole != nsIAccessibleRole::ROLE_RADIO_MENU_ITEM &&
-      aRole != nsIAccessibleRole::ROLE_RADIOBUTTON &&
-      aRole != nsIAccessibleRole::ROLE_PAGETAB &&
-      aRole != nsIAccessibleRole::ROLE_OPTION &&
-      aRole != nsIAccessibleRole::ROLE_OUTLINEITEM &&
-      aRole != nsIAccessibleRole::ROLE_ROW &&
-      aRole != nsIAccessibleRole::ROLE_GRID_CELL)
-    return NS_OK;
-
-  PRUint32 baseRole = aRole;
-  if (aRole == nsIAccessibleRole::ROLE_CHECK_MENU_ITEM ||
-      aRole == nsIAccessibleRole::ROLE_RADIO_MENU_ITEM)
+  PRUint32 role = nsAccUtils::Role(this);
+  if (role != nsIAccessibleRole::ROLE_LISTITEM &&
+      role != nsIAccessibleRole::ROLE_MENUITEM &&
+      role != nsIAccessibleRole::ROLE_CHECK_MENU_ITEM &&
+      role != nsIAccessibleRole::ROLE_RADIO_MENU_ITEM &&
+      role != nsIAccessibleRole::ROLE_RADIOBUTTON &&
+      role != nsIAccessibleRole::ROLE_PAGETAB &&
+      role != nsIAccessibleRole::ROLE_OPTION &&
+      role != nsIAccessibleRole::ROLE_OUTLINEITEM &&
+      role != nsIAccessibleRole::ROLE_ROW &&
+      role != nsIAccessibleRole::ROLE_GRID_CELL)
+    return;
+
+  PRUint32 baseRole = role;
+  if (role == nsIAccessibleRole::ROLE_CHECK_MENU_ITEM ||
+      role == nsIAccessibleRole::ROLE_RADIO_MENU_ITEM)
     baseRole = nsIAccessibleRole::ROLE_MENUITEM;
 
   nsCOMPtr<nsIAccessible> parent = GetParent();
-  NS_ENSURE_TRUE(parent, NS_ERROR_FAILURE);
+  NS_ENSURE_TRUE(parent,);
 
   // Compute 'posinset' and 'setsize' attributes.
   PRInt32 positionInGroup = 0;
   PRInt32 setSize = 0;
 
   nsCOMPtr<nsIAccessible> sibling, nextSibling;
   parent->GetFirstChild(getter_AddRefs(sibling));
-  NS_ENSURE_STATE(sibling);
+  NS_ENSURE_TRUE(sibling,);
 
   PRBool foundCurrent = PR_FALSE;
   PRUint32 siblingRole, siblingBaseRole;
   while (sibling) {
     siblingRole = nsAccUtils::Role(sibling);
 
     siblingBaseRole = siblingRole;
     if (siblingRole == nsIAccessibleRole::ROLE_CHECK_MENU_ITEM ||
@@ -3364,79 +3384,94 @@ nsAccessible::ComputeGroupAttributes(PRU
       positionInGroup = 0;
       setSize = 0;
     }
 
     sibling->GetNextSibling(getter_AddRefs(nextSibling));
     sibling = nextSibling;
   }
 
-  // Compute 'level' attribute.
-  PRInt32 groupLevel = 0;
-  if (aRole == nsIAccessibleRole::ROLE_OUTLINEITEM) {
+  *aPosInSet = positionInGroup;
+  *aSetSize = setSize;
+}
+
+PRInt32
+nsAccessible::GetLevelInternal()
+{
+  PRUint32 role = nsAccUtils::Role(this);
+  nsCOMPtr<nsIAccessible> parent = GetParent();
+
+  if (role == nsIAccessibleRole::ROLE_OUTLINEITEM) {
     // Always expose 'level' attribute for 'outlineitem' accessible. The number
     // of nested 'grouping' accessibles containing 'outlineitem' accessible is
     // its level.
-    groupLevel = 1;
+    PRInt32 level = 1;
     nsCOMPtr<nsIAccessible> nextParent;
     while (parent) {
       PRUint32 parentRole = nsAccUtils::Role(parent);
 
       if (parentRole == nsIAccessibleRole::ROLE_OUTLINE)
         break;
       if (parentRole == nsIAccessibleRole::ROLE_GROUPING)
-        ++ groupLevel;
+        ++ level;
 
       parent->GetParent(getter_AddRefs(nextParent));
       parent.swap(nextParent);
     }
-  } else if (aRole == nsIAccessibleRole::ROLE_LISTITEM) {
+
+    return level;
+  }
+
+  if (role == nsIAccessibleRole::ROLE_LISTITEM) {
     // Expose 'level' attribute on nested lists. We assume nested list is a last
     // child of listitem of parent list. We don't handle the case when nested
     // lists have more complex structure, for example when there are accessibles
     // between parent listitem and nested list.
 
     // Calculate 'level' attribute based on number of parent listitems.
+    PRInt32 level = 0;
     nsCOMPtr<nsIAccessible> nextParent;
+
     while (parent) {
       PRUint32 parentRole = nsAccUtils::Role(parent);
 
       if (parentRole == nsIAccessibleRole::ROLE_LISTITEM)
-        ++ groupLevel;
+        ++ level;
       else if (parentRole != nsIAccessibleRole::ROLE_LIST)
         break;
 
       parent->GetParent(getter_AddRefs(nextParent));
       parent.swap(nextParent);
     }
 
-    if (groupLevel == 0) {
+    if (level == 0) {
       // If this listitem is on top of nested lists then expose 'level'
       // attribute.
-      nsCOMPtr<nsIAccessible> parent = GetParent();
+      nsCOMPtr<nsIAccessible> parent(GetParent()), sibling, nextSibling;
       parent->GetFirstChild(getter_AddRefs(sibling));
 
       while (sibling) {
         nsCOMPtr<nsIAccessible> siblingChild;
         sibling->GetLastChild(getter_AddRefs(siblingChild));
         if (nsAccUtils::Role(siblingChild) == nsIAccessibleRole::ROLE_LIST) {
-          groupLevel = 1;
+          level = 1;
           break;
         }
 
         sibling->GetNextSibling(getter_AddRefs(nextSibling));
         sibling.swap(nextSibling);
       }
-    } else
-      groupLevel++; // level is 1-index based
-
-  } else if (aRole == nsIAccessibleRole::ROLE_ROW &&
-             nsAccUtils::Role(GetParent()) == nsIAccessibleRole::ROLE_TREE_TABLE) {
+    } else {
+      ++ level; // level is 1-index based
+    }
+
+    return level;
+  }
+
+  if (role == nsIAccessibleRole::ROLE_ROW &&
+      nsAccUtils::Role(parent) == nsIAccessibleRole::ROLE_TREE_TABLE) {
     // It is a row inside flatten treegrid. Group level is always 1 until it is
     // overriden by aria-level attribute.
-    groupLevel = 1;
+    return 1;
   }
 
-  nsAccUtils::SetAccGroupAttrs(aAttributes, groupLevel, positionInGroup,
-                               setSize);
-
-  return NS_OK;
+  return 0;
 }
--- a/accessible/src/base/nsAccessible.h
+++ b/accessible/src/base/nsAccessible.h
@@ -98,21 +98,21 @@ public:
   }
 
 private:
   nsTArray<nsString> mNames;
 };
 
 
 #define NS_ACCESSIBLE_IMPL_CID                          \
-{  /* 07c5a6d6-4e87-4b57-8613-4c39e1b5150a */           \
-  0x07c5a6d6,                                           \
-  0x4e87,                                               \
-  0x4b57,                                               \
-  { 0x86, 0x13, 0x4c, 0x39, 0xe1, 0xb5, 0x15, 0x0a }    \
+{  /* 81a84b69-de5a-412f-85ff-deb005c5a68d */           \
+  0x81a84b69,                                           \
+  0xde5a,                                               \
+  0x412f,                                               \
+  { 0x85, 0xff, 0xde, 0xb0, 0x05, 0xc5, 0xa6, 0x8d }    \
 }
 
 class nsAccessible : public nsAccessNodeWrap, 
                      public nsIAccessible, 
                      public nsIAccessibleHyperLink,
                      public nsIAccessibleSelectable,
                      public nsIAccessibleValue
 {
@@ -193,16 +193,31 @@ public:
    * @param  aY             [in] y coordinate relative screen
    * @param  aDeepestChild  [in] flag points if deep child should be returned
    * @param  aChild         [out] found child
    */
   virtual nsresult GetChildAtPoint(PRInt32 aX, PRInt32 aY,
                                    PRBool aDeepestChild,
                                    nsIAccessible **aChild);
 
+  /**
+   * Return calculated group level based on accessible hierarchy.
+   */
+  virtual PRInt32 GetLevelInternal();
+
+  /**
+   * Calculate position in group and group size ('posinset' and 'setsize') based
+   * on accessible hierarchy.
+   *
+   * @param  aPosInSet  [out] accessible position in the group
+   * @param  aSetSize   [out] the group size
+   */
+  virtual void GetPositionAndSizeInternal(PRInt32 *aPosInSet,
+                                          PRInt32 *aSetSize);
+
   //////////////////////////////////////////////////////////////////////////////
   // Initializing methods
 
   /**
    * Set the ARIA role map entry for a new accessible.
    * For a newly created accessible, specify which role map entry should be used.
    *
    * @param aRoleMapEntry The ARIA nsRoleMapEntry* for the accessible, or 
@@ -424,27 +439,16 @@ protected:
    * Return the action rule based on ARIA enum constants EActionRule
    * (see nsARIAMap.h). Used by GetNumActions() and GetActionName().
    *
    * @param aStates  [in] states of the accessible
    */
   PRUint32 GetActionRule(PRUint32 aStates);
 
   /**
-   * Compute group attributes ('posinset', 'setsize' and 'level') based
-   * on accessible hierarchy. Used by GetAttributes() method if group attributes
-   * weren't provided by ARIA or by internal accessible implementation.
-   *
-   * @param  aRole        [in] role of this accessible
-   * @param  aAttributes  [in, out] object attributes
-   */
-  nsresult ComputeGroupAttributes(PRUint32 aRole,
-                                  nsIPersistentProperties *aAttributes);
-
-  /**
    * Fires platform accessible event. It's notification method only. It does
    * change nothing on Gecko side. Mostly you should use
    * nsIAccessible::FireAccessibleEvent excepting special cases like we have
    * in xul:tree accessible to lie to AT. Must be overridden in wrap classes.
    *
    * @param aEvent  the accessible event to fire.
    */
   virtual nsresult FirePlatformEvent(nsIAccessibleEvent *aEvent) = 0;
--- a/accessible/src/html/nsHTMLFormControlAccessible.cpp
+++ b/accessible/src/html/nsHTMLFormControlAccessible.cpp
@@ -136,17 +136,19 @@ nsHTMLCheckboxAccessible::GetStateIntern
   
     if (checked)
       *aState |= nsIAccessibleStates::STATE_CHECKED;
   }
 
   return NS_OK;
 }
 
-//------ Radio button -------
+////////////////////////////////////////////////////////////////////////////////
+// nsHTMLRadioButtonAccessible
+////////////////////////////////////////////////////////////////////////////////
 
 nsHTMLRadioButtonAccessible::nsHTMLRadioButtonAccessible(nsIDOMNode* aNode, nsIWeakReference* aShell):
 nsRadioButtonAccessible(aNode, aShell)
 { 
 }
 
 nsresult
 nsHTMLRadioButtonAccessible::GetStateInternal(PRUint32 *aState,
@@ -164,32 +166,26 @@ nsHTMLRadioButtonAccessible::GetStateInt
     htmlRadioElement->GetChecked(&checked);
 
   if (checked)
     *aState |= nsIAccessibleStates::STATE_CHECKED;
 
   return NS_OK;
 }
 
-nsresult
-nsHTMLRadioButtonAccessible::GetAttributesInternal(nsIPersistentProperties *aAttributes)
+void
+nsHTMLRadioButtonAccessible::GetPositionAndSizeInternal(PRInt32 *aPosInSet,
+                                                        PRInt32 *aSetSize)
 {
-  NS_ENSURE_ARG_POINTER(aAttributes);
-  NS_ENSURE_TRUE(mDOMNode, NS_ERROR_FAILURE);
-
-  nsresult rv = nsRadioButtonAccessible::GetAttributesInternal(aAttributes);
-  NS_ENSURE_SUCCESS(rv, rv);
-
   nsAutoString nsURI;
   mDOMNode->GetNamespaceURI(nsURI);
   nsAutoString tagName;
   mDOMNode->GetLocalName(tagName);
 
   nsCOMPtr<nsIContent> content(do_QueryInterface(mDOMNode));
-  NS_ENSURE_STATE(content);
 
   nsAutoString type;
   content->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::type, type);
   nsAutoString name;
   content->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::name, name);
 
   nsCOMPtr<nsIDOMNodeList> inputs;
 
@@ -200,22 +196,22 @@ nsHTMLRadioButtonAccessible::GetAttribut
     form->GetElementsByTagNameNS(nsURI, tagName, getter_AddRefs(inputs));
   } else {
     nsCOMPtr<nsIDOMDocument> document;
     mDOMNode->GetOwnerDocument(getter_AddRefs(document));
     if (document)
       document->GetElementsByTagNameNS(nsURI, tagName, getter_AddRefs(inputs));
   }
 
-  NS_ENSURE_TRUE(inputs, NS_OK);
+  NS_ENSURE_TRUE(inputs, );
 
   PRUint32 inputsCount = 0;
   inputs->GetLength(&inputsCount);
 
-  // Get posinset and setsize.
+  // Compute posinset and setsize.
   PRInt32 indexOf = 0;
   PRInt32 count = 0;
 
   for (PRUint32 index = 0; index < inputsCount; index++) {
     nsCOMPtr<nsIDOMNode> itemNode;
     inputs->Item(index, getter_AddRefs(itemNode));
 
     nsCOMPtr<nsIContent> item(do_QueryInterface(itemNode));
@@ -227,22 +223,23 @@ nsHTMLRadioButtonAccessible::GetAttribut
 
       count++;
 
       if (itemNode == mDOMNode)
         indexOf = count;
     }
   }
 
-  nsAccUtils::SetAccGroupAttrs(aAttributes, 0, indexOf, count);
-
-  return  NS_OK;
+  *aPosInSet = indexOf;
+  *aSetSize = count;
 }
 
-// ----- Button -----
+////////////////////////////////////////////////////////////////////////////////
+// nsHTMLButtonAccessible
+////////////////////////////////////////////////////////////////////////////////
 
 nsHTMLButtonAccessible::nsHTMLButtonAccessible(nsIDOMNode* aNode, nsIWeakReference* aShell):
 nsHyperTextAccessibleWrap(aNode, aShell)
 { 
 }
 
 NS_IMETHODIMP nsHTMLButtonAccessible::GetNumActions(PRUint8 *_retval)
 {
--- a/accessible/src/html/nsHTMLFormControlAccessible.h
+++ b/accessible/src/html/nsHTMLFormControlAccessible.h
@@ -62,18 +62,19 @@ public:
 
 class nsHTMLRadioButtonAccessible : public nsRadioButtonAccessible
 {
 
 public:
   nsHTMLRadioButtonAccessible(nsIDOMNode* aNode, nsIWeakReference* aShell);
 
   // nsAccessible
-  virtual nsresult GetAttributesInternal(nsIPersistentProperties *aAttributes);
   virtual nsresult GetStateInternal(PRUint32 *aState, PRUint32 *aExtraState);
+  virtual void GetPositionAndSizeInternal(PRInt32 *aPosInSet,
+                                          PRInt32 *aSetSize);
 };
 
 class nsHTMLButtonAccessible : public nsHyperTextAccessibleWrap
 {
 
 public:
   enum { eAction_Click = 0 };
 
--- a/accessible/src/html/nsHTMLSelectAccessible.cpp
+++ b/accessible/src/html/nsHTMLSelectAccessible.cpp
@@ -443,17 +443,19 @@ nsHyperTextAccessibleWrap(aDOMNode, aShe
         nsCOMPtr<nsIAccessible> comboAccessible(parentAccessible);
         comboAccessible->GetLastChild(getter_AddRefs(parentAccessible));
       }
     }
   }
   SetParent(parentAccessible);
 }
 
-/** We are a ListItem */
+////////////////////////////////////////////////////////////////////////////////
+// nsHTMLSelectOptionAccessible: nsAccessible public
+
 nsresult
 nsHTMLSelectOptionAccessible::GetRoleInternal(PRUint32 *aRole)
 {
   if (nsAccUtils::Role(mParent) == nsIAccessibleRole::ROLE_COMBOBOX_LIST)
     *aRole = nsIAccessibleRole::ROLE_COMBOBOX_OPTION;
   else
     *aRole = nsIAccessibleRole::ROLE_OPTION;
 
@@ -486,59 +488,16 @@ nsHTMLSelectOptionAccessible::GetNameInt
     txtValue.CompressWhitespace();
     aName.Assign(txtValue);
     return NS_OK;
   }
 
   return NS_OK;
 }
 
-nsresult
-nsHTMLSelectOptionAccessible::GetAttributesInternal(nsIPersistentProperties *aAttributes)
-{
-  NS_ENSURE_ARG_POINTER(aAttributes);
-  if (!mDOMNode) {
-    return NS_ERROR_FAILURE;  // Accessible shut down
-  }
-
-  nsresult rv = nsHyperTextAccessibleWrap::GetAttributesInternal(aAttributes);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  nsCOMPtr<nsIDOMNode> parentNode;
-  mDOMNode->GetParentNode(getter_AddRefs(parentNode));
-  nsCOMPtr<nsIDOMElement> parentElement(do_QueryInterface(parentNode));
-  NS_ENSURE_TRUE(parentElement, NS_ERROR_FAILURE);
-  nsAutoString parentTagName;
-  parentNode->GetLocalName(parentTagName);
-
-  PRInt32 level = parentTagName.LowerCaseEqualsLiteral("optgroup") ? 2 : 1;
-  if (level == 1 && nsAccUtils::Role(this) != nsIAccessibleRole::ROLE_HEADING) {
-    level = 0; // In a single level list, the level is irrelevant
-  }
-
-  nsAutoString tagName;
-  mDOMNode->GetLocalName(tagName);  // Will be looking for similar DOM siblings
-  nsCOMPtr<nsIDOMNodeList> siblings;
-  parentElement->GetElementsByTagName(tagName, getter_AddRefs(siblings));
-  PRInt32 posInSet = 0;
-  PRUint32 setSize = 0;
-  if (siblings) {
-    siblings->GetLength(&setSize);
-    nsCOMPtr<nsIDOMNode> itemNode;
-    while (NS_SUCCEEDED(siblings->Item(posInSet ++, getter_AddRefs(itemNode))) &&
-           itemNode != mDOMNode) {
-      // Keep looping, to increment posInSet
-    }
-  }
-
-  nsAccUtils::SetAccGroupAttrs(aAttributes, level, posInSet,
-                               static_cast<PRInt32>(setSize));
-  return  NS_OK;
-}
-
 nsIFrame* nsHTMLSelectOptionAccessible::GetBoundsFrame()
 {
   PRUint32 state;
   nsCOMPtr<nsIContent> content = GetSelectState(&state);
   if (state & nsIAccessibleStates::STATE_COLLAPSED) {
     if (content) {
       return content->GetPrimaryFrame();
     }
@@ -636,16 +595,64 @@ nsHTMLSelectOptionAccessible::GetStateIn
         *aState |= nsIAccessibleStates::STATE_OFFSCREEN;
       }
     }
   }
  
   return NS_OK;
 }
 
+PRInt32
+nsHTMLSelectOptionAccessible::GetLevelInternal()
+{
+  nsCOMPtr<nsIContent> content(do_QueryInterface(mDOMNode));
+  nsIContent *parentContent = content->GetParent();
+
+  PRInt32 level =
+    parentContent->NodeInfo()->Equals(nsAccessibilityAtoms::optgroup) ? 2 : 1;
+
+  if (level == 1 &&
+      nsAccUtils::Role(this) != nsIAccessibleRole::ROLE_HEADING) {
+    level = 0; // In a single level list, the level is irrelevant
+  }
+
+  return level;
+}
+
+void
+nsHTMLSelectOptionAccessible::GetPositionAndSizeInternal(PRInt32 *aPosInSet,
+                                                         PRInt32 *aSetSize)
+{  
+  nsCOMPtr<nsIContent> content(do_QueryInterface(mDOMNode));
+  nsIContent *parentContent = content->GetParent();
+
+  PRInt32 posInSet = 0, setSize = 0;
+  PRBool isContentFound = PR_FALSE;
+
+  PRUint32 childCount = parentContent->GetChildCount();
+  for (PRUint32 childIdx = 0; childIdx < childCount; childIdx++) {
+    nsIContent *childContent = parentContent->GetChildAt(childIdx);
+    if (childContent->NodeInfo()->Equals(content->NodeInfo())) {
+      if (!isContentFound) {
+        if (childContent == content)
+          isContentFound = PR_TRUE;
+
+        posInSet++;
+      }
+      setSize++;
+    }
+  }
+
+  *aSetSize = setSize;
+  *aPosInSet = posInSet;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// nsHTMLSelectOptionAccessible: nsIAccessible
+
 /** select us! close combo box if necessary*/
 NS_IMETHODIMP nsHTMLSelectOptionAccessible::GetActionName(PRUint8 aIndex, nsAString& aName)
 {
   if (aIndex == eAction_Select) {
     aName.AssignLiteral("select"); 
     return NS_OK;
   }
   return NS_ERROR_INVALID_ARG;
@@ -710,16 +717,19 @@ NS_IMETHODIMP nsHTMLSelectOptionAccessib
       }
     }
     return NS_OK;
   }
 
   return NS_ERROR_INVALID_ARG;
 }
 
+////////////////////////////////////////////////////////////////////////////////
+// nsHTMLSelectOptionAccessible: static methods
+
 /**
   * Helper method for getting the focused DOM Node from our parent(list) node. We
   *  need to use the frame to get the focused option because for some reason we
   *  weren't getting the proper notification when the focus changed using the DOM
   */
 nsresult nsHTMLSelectOptionAccessible::GetFocusedOptionNode(nsIDOMNode *aListNode, 
                                                             nsIDOMNode **aFocusedOptionNode)
 {
@@ -808,16 +818,19 @@ void nsHTMLSelectOptionAccessible::Selec
   }
   else {
     eventType = nsIAccessibleEvent::EVENT_SELECTION_REMOVE;
   }
 
   nsAccUtils::FireAccEvent(eventType, optionAccessible);
 }
 
+////////////////////////////////////////////////////////////////////////////////
+// nsHTMLSelectOptionAccessible: private methods
+
 nsIContent* nsHTMLSelectOptionAccessible::GetSelectState(PRUint32* aState,
                                                          PRUint32* aExtraState)
 {
   nsCOMPtr<nsIContent> content(do_QueryInterface(mDOMNode));
   while (content && content->Tag() != nsAccessibilityAtoms::select) {
     content = content->GetParent();
   }
 
--- a/accessible/src/html/nsHTMLSelectAccessible.h
+++ b/accessible/src/html/nsHTMLSelectAccessible.h
@@ -157,17 +157,20 @@ public:
   NS_IMETHOD DoAction(PRUint8 index);
   NS_IMETHOD GetActionName(PRUint8 aIndex, nsAString& aName);
   NS_IMETHOD GetNumActions(PRUint8 *_retval);
 
   // nsAccessible
   virtual nsresult GetNameInternal(nsAString& aName);
   virtual nsresult GetRoleInternal(PRUint32 *aRole);
   virtual nsresult GetStateInternal(PRUint32 *aState, PRUint32 *aExtraState);
-  virtual nsresult GetAttributesInternal(nsIPersistentProperties *aAttributes);
+
+  virtual PRInt32 GetLevelInternal();
+  virtual void GetPositionAndSizeInternal(PRInt32 *aPosInSet,
+                                          PRInt32 *aSetSize);
 
   nsIFrame*  GetBoundsFrame();
   static nsresult GetFocusedOptionNode(nsIDOMNode *aListNode, nsIDOMNode **aFocusedOptionNode);
   static void SelectionChangedIfOption(nsIContent *aPossibleOption);
 
 private:
   
   /**
--- a/accessible/src/html/nsHyperTextAccessible.cpp
+++ b/accessible/src/html/nsHyperTextAccessible.cpp
@@ -1189,51 +1189,45 @@ nsHyperTextAccessible::GetDefaultTextAtt
 
   if (!mDOMNode)
     return NS_ERROR_FAILURE;
 
   nsTextAttrsMgr textAttrsMgr(this, mDOMNode, PR_TRUE, nsnull);
   return textAttrsMgr.GetAttributes(*aAttributes);
 }
 
+PRInt32
+nsHyperTextAccessible::GetLevelInternal()
+{
+  nsCOMPtr<nsIContent> content = nsCoreUtils::GetRoleContent(mDOMNode);
+  NS_ENSURE_TRUE(content, 0);
+
+  nsIAtom *tag = content->Tag();
+  if (tag == nsAccessibilityAtoms::h1)
+    return 1;
+  if (tag == nsAccessibilityAtoms::h2)
+    return 2;
+  if (tag == nsAccessibilityAtoms::h3)
+    return 3;
+  if (tag == nsAccessibilityAtoms::h4)
+    return 4;
+  if (tag == nsAccessibilityAtoms::h5)
+    return 5;
+  if (tag == nsAccessibilityAtoms::h6)
+    return 6;
+
+  return nsAccessibleWrap::GetLevelInternal();
+}
+
 nsresult
 nsHyperTextAccessible::GetAttributesInternal(nsIPersistentProperties *aAttributes)
 {
-  if (!mDOMNode) {
-    return NS_ERROR_FAILURE;  // Node already shut down
-  }
-
   nsresult rv = nsAccessibleWrap::GetAttributesInternal(aAttributes);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  nsCOMPtr<nsIContent> content = nsCoreUtils::GetRoleContent(mDOMNode);
-  NS_ENSURE_TRUE(content, NS_ERROR_UNEXPECTED);
-  nsIAtom *tag = content->Tag();
-
-  PRInt32 headLevel = 0;
-  if (tag == nsAccessibilityAtoms::h1)
-    headLevel = 1;
-  else if (tag == nsAccessibilityAtoms::h2)
-    headLevel = 2;
-  else if (tag == nsAccessibilityAtoms::h3)
-    headLevel = 3;
-  else if (tag == nsAccessibilityAtoms::h4)
-    headLevel = 4;
-  else if (tag == nsAccessibilityAtoms::h5)
-    headLevel = 5;
-  else if (tag == nsAccessibilityAtoms::h6)
-    headLevel = 6;
-
-  if (headLevel) {
-    nsAutoString strHeadLevel;
-    strHeadLevel.AppendInt(headLevel);
-    nsAccUtils::SetAccAttr(aAttributes, nsAccessibilityAtoms::level,
-                           strHeadLevel);
-  }
-  
   // Indicate when the current object uses block-level formatting
   // via formatting: block
   // XXX: 'formatting' attribute is deprecated and will be removed in Mozilla2,
   // use 'display' attribute instead.
   nsIFrame *frame = GetFrame();
   if (frame && frame->GetType() == nsAccessibilityAtoms::blockFrame) {
     nsAutoString oldValueUnused;
     aAttributes->SetStringProperty(NS_LITERAL_CSTRING("formatting"), NS_LITERAL_STRING("block"),
--- a/accessible/src/html/nsHyperTextAccessible.h
+++ b/accessible/src/html/nsHyperTextAccessible.h
@@ -78,16 +78,17 @@ public:
   nsHyperTextAccessible(nsIDOMNode* aNode, nsIWeakReference* aShell);
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_NSIACCESSIBLETEXT
   NS_DECL_NSIACCESSIBLEHYPERTEXT
   NS_DECL_NSIACCESSIBLEEDITABLETEXT
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_HYPERTEXTACCESSIBLE_IMPL_CID)
 
   // nsAccessible
+  virtual PRInt32 GetLevelInternal();
   virtual nsresult GetAttributesInternal(nsIPersistentProperties *aAttributes);
   virtual nsresult GetRoleInternal(PRUint32 *aRole);
   virtual nsresult GetStateInternal(PRUint32 *aState, PRUint32 *aExtraState);
 
   // Convert content offset to rendered text offset  
   static nsresult ContentToRenderedOffset(nsIFrame *aFrame, PRInt32 aContentOffset,
                                           PRUint32 *aRenderedOffset);
   
--- a/accessible/src/msaa/nsAccessibleWrap.cpp
+++ b/accessible/src/msaa/nsAccessibleWrap.cpp
@@ -365,30 +365,21 @@ nsAccessibleWrap::get_accDescription(VAR
     return E_FAIL;
 
   // For items that are a choice in a list of choices, use MSAA description
   // field to shoehorn positional info, it's becoming a defacto standard use for
   // the field.
 
   nsAutoString description;
 
-  // Try to get group attributes to make a positional description string. We
-  // can't use nsIAccessible::groupPosition because the method isn't supposed
-  // to work with elements exposing 'level' attribute only (like HTML headings).
-  nsCOMPtr<nsIPersistentProperties> attributes;
-  nsresult rv = xpAccessible->GetAttributes(getter_AddRefs(attributes));
-  NS_ENSURE_SUCCESS(rv, rv);
-  if (!attributes)
-    return NS_ERROR_FAILURE;
-
+  // Try to get group position to make a positional description string.
   PRInt32 groupLevel = 0;
   PRInt32 itemsInGroup = 0;
   PRInt32 positionInGroup = 0;
-  nsAccUtils::GetAccGroupAttrs(attributes, &groupLevel, &positionInGroup,
-                               &itemsInGroup);
+  GroupPosition(&groupLevel, &itemsInGroup, &positionInGroup);
 
   if (positionInGroup > 0) {
     if (groupLevel > 0) {
       // XXX: How do we calculate the number of children? Now we append
       // " with [numChildren]c" for tree item. In the future we may need to
       // use the ARIA owns property to calculate that if it's present.
       PRInt32 numChildren = 0;
 
@@ -1335,28 +1326,32 @@ STDMETHODIMP
 nsAccessibleWrap::get_groupPosition(long *aGroupLevel,
                                     long *aSimilarItemsInGroup,
                                     long *aPositionInGroup)
 {
 __try {
   PRInt32 groupLevel = 0;
   PRInt32 similarItemsInGroup = 0;
   PRInt32 positionInGroup = 0;
+
   nsresult rv = GroupPosition(&groupLevel, &similarItemsInGroup,
                               &positionInGroup);
+  if (NS_FAILED(rv))
+    return GetHRESULT(rv);
+
+  // Group information for accessibles having level only (like html headings
+  // elements) isn't exposed by this method. AT should look for 'level' object
+  // attribute.
+  if (!similarItemsInGroup && !positionInGroup)
+    return S_FALSE;
 
   *aGroupLevel = groupLevel;
   *aSimilarItemsInGroup = similarItemsInGroup;
   *aPositionInGroup = positionInGroup;
 
-  if (NS_FAILED(rv))
-    return GetHRESULT(rv);
-
-  if (groupLevel ==0 && similarItemsInGroup == 0 && positionInGroup == 0)
-    return S_FALSE;
   return S_OK;
 
 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
   return E_FAIL;
 }
 
 STDMETHODIMP
 nsAccessibleWrap::get_states(AccessibleStates *aStates)
--- a/accessible/src/xul/nsXULFormControlAccessible.cpp
+++ b/accessible/src/xul/nsXULFormControlAccessible.cpp
@@ -654,19 +654,19 @@ nsXULProgressMeterAccessible::GetCurrent
 
 NS_IMETHODIMP
 nsXULProgressMeterAccessible::SetCurrentValue(double aValue)
 {
   return NS_ERROR_FAILURE; // Progress meters are readonly!
 }
 
 
-/**
-  * XUL Radio Button
-  */
+////////////////////////////////////////////////////////////////////////////////
+// nsXULRadioButtonAccessible
+////////////////////////////////////////////////////////////////////////////////
 
 /** Constructor */
 nsXULRadioButtonAccessible::nsXULRadioButtonAccessible(nsIDOMNode* aNode, nsIWeakReference* aShell):
 nsRadioButtonAccessible(aNode, aShell)
 { 
 }
 
 /** We are Focusable and can be Checked and focused */
@@ -687,29 +687,28 @@ nsXULRadioButtonAccessible::GetStateInte
     if (selected) {
       *aState |= nsIAccessibleStates::STATE_CHECKED;
     }
   }
 
   return NS_OK;
 }
 
-nsresult
-nsXULRadioButtonAccessible::GetAttributesInternal(nsIPersistentProperties *aAttributes)
+void
+nsXULRadioButtonAccessible::GetPositionAndSizeInternal(PRInt32 *aPosInSet,
+                                                       PRInt32 *aSetSize)
 {
-  NS_ENSURE_ARG_POINTER(aAttributes);
-  NS_ENSURE_TRUE(mDOMNode, NS_ERROR_FAILURE);
+  nsAccUtils::GetPositionAndSizeForXULSelectControlItem(mDOMNode, aPosInSet,
+                                                        aSetSize);
+}
 
-  nsresult rv = nsFormControlAccessible::GetAttributesInternal(aAttributes);
-  NS_ENSURE_SUCCESS(rv, rv);
 
-  nsAccUtils::SetAccAttrsForXULSelectControlItem(mDOMNode, aAttributes);
-
-  return NS_OK;
-}
+////////////////////////////////////////////////////////////////////////////////
+// nsXULRadioGroupAccessible
+////////////////////////////////////////////////////////////////////////////////
 
 /**
   * XUL Radio Group
   *   The Radio Group proxies for the Radio Buttons themselves. The Group gets
   *   focus whereas the Buttons do not. So we only have an accessible object for
   *   this for the purpose of getting the proper RadioButton. Need this here to 
   *   avoid circular reference problems when navigating the accessible tree and
   *   for getting to the radiobuttons.
@@ -768,25 +767,20 @@ nsXULStatusBarAccessible::GetRoleInterna
 /**
   * XUL Toolbar Button
   */
 nsXULToolbarButtonAccessible::nsXULToolbarButtonAccessible(nsIDOMNode* aNode, nsIWeakReference* aShell):
 nsXULButtonAccessible(aNode, aShell)
 {
 }
 
-nsresult
-nsXULToolbarButtonAccessible::GetAttributesInternal(nsIPersistentProperties *aAttributes)
+void
+nsXULToolbarButtonAccessible::GetPositionAndSizeInternal(PRInt32 *aPosInSet,
+                                                         PRInt32 *aSetSize)
 {
-  NS_ENSURE_ARG_POINTER(aAttributes);
-  NS_ENSURE_TRUE(mDOMNode, NS_ERROR_FAILURE);
-
-  nsresult rv = nsXULButtonAccessible::GetAttributesInternal(aAttributes);
-  NS_ENSURE_SUCCESS(rv, rv);
-
   nsCOMPtr<nsIAccessible> parent(GetParent());
   PRInt32 setSize = 0;
   PRInt32 posInSet = 0;
 
   if (parent) {
     nsCOMPtr<nsIAccessible> sibling;
     nsCOMPtr<nsIAccessible> tempSibling;
     parent->GetFirstChild(getter_AddRefs(sibling));
@@ -799,20 +793,19 @@ nsXULToolbarButtonAccessible::GetAttribu
         setSize++; // another button in the group
         if (sibling == this)
           posInSet = setSize; // we've found our button
       }
       sibling->GetNextSibling(getter_AddRefs(tempSibling));
       sibling.swap(tempSibling);
     }
   }
-  
-  nsAccUtils::SetAccGroupAttrs(aAttributes, 0, posInSet, setSize);
 
-  return NS_OK;
+  *aPosInSet = posInSet;
+  *aSetSize = setSize;
 }
 
 PRBool
 nsXULToolbarButtonAccessible::IsSeparator(nsIAccessible *aAccessible)
 {
   nsCOMPtr<nsIDOMNode> domNode;
   nsCOMPtr<nsIAccessNode> accessNode(do_QueryInterface(aAccessible));
   accessNode->GetDOMNode(getter_AddRefs(domNode));
--- a/accessible/src/xul/nsXULFormControlAccessible.h
+++ b/accessible/src/xul/nsXULFormControlAccessible.h
@@ -143,25 +143,29 @@ class nsXULProgressMeterAccessible : pub
 public:
   nsXULProgressMeterAccessible(nsIDOMNode* aNode, nsIWeakReference* aShell);
   NS_IMETHOD GetValue(nsAString &aValue);
 
   // nsAccessible
   virtual nsresult GetRoleInternal(PRUint32 *aRole);
 };
 
+/**
+ * Used for XUL radio button (xul:radio).
+ */
 class nsXULRadioButtonAccessible : public nsRadioButtonAccessible
 {
 
 public:
   nsXULRadioButtonAccessible(nsIDOMNode* aNode, nsIWeakReference* aShell);
 
   // nsAccessible
-  virtual nsresult GetAttributesInternal(nsIPersistentProperties *aAttributes);
   virtual nsresult GetStateInternal(PRUint32 *aState, PRUint32 *aExtraState);
+  virtual void GetPositionAndSizeInternal(PRInt32 *aPosInSet,
+                                          PRInt32 *aSetSize);
 };
 
 class nsXULRadioGroupAccessible : public nsXULSelectableAccessible
 {
 public:
   nsXULRadioGroupAccessible(nsIDOMNode* aNode, nsIWeakReference* aShell);
 
   // nsAccessible
@@ -177,17 +181,21 @@ public:
   // nsAccessible
   virtual nsresult GetRoleInternal(PRUint32 *aRole);
 };
 
 class nsXULToolbarButtonAccessible : public nsXULButtonAccessible
 {
 public:
   nsXULToolbarButtonAccessible(nsIDOMNode* aNode, nsIWeakReference* aShell);
-  virtual nsresult GetAttributesInternal(nsIPersistentProperties *aAttributes);
+
+  // nsAccessible
+  virtual void GetPositionAndSizeInternal(PRInt32 *aPosInSet,
+                                          PRInt32 *aSetSize);
+
   static PRBool IsSeparator(nsIAccessible *aAccessible);
 };
 
 class nsXULToolbarAccessible : public nsAccessibleWrap
 {
 public:
   nsXULToolbarAccessible(nsIDOMNode* aNode, nsIWeakReference* aShell);
 
--- a/accessible/src/xul/nsXULListboxAccessible.cpp
+++ b/accessible/src/xul/nsXULListboxAccessible.cpp
@@ -1004,29 +1004,22 @@ NS_IMETHODIMP nsXULListitemAccessible::G
 
 PRBool
 nsXULListitemAccessible::GetAllowsAnonChildAccessibles()
 {
   // That indicates we should walk anonymous children for listitems
   return PR_TRUE;
 }
 
-nsresult
-nsXULListitemAccessible::GetAttributesInternal(nsIPersistentProperties *aAttributes)
+void
+nsXULListitemAccessible::GetPositionAndSizeInternal(PRInt32 *aPosInSet,
+                                                    PRInt32 *aSetSize)
 {
-  NS_ENSURE_ARG_POINTER(aAttributes);
-
-  // Call base class instead of nsXULMenuAccessible because menu accessible
-  // has own implementation of group attributes setting which interferes with
-  // this one.
-  nsresult rv = nsAccessible::GetAttributesInternal(aAttributes);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  nsAccUtils::SetAccAttrsForXULSelectControlItem(mDOMNode, aAttributes);
-  return NS_OK;
+  nsAccUtils::GetPositionAndSizeForXULSelectControlItem(mDOMNode, aPosInSet,
+                                                        aSetSize);
 }
 
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsXULListCellAccessible
 ////////////////////////////////////////////////////////////////////////////////
 
 nsXULListCellAccessible::
--- a/accessible/src/xul/nsXULListboxAccessible.h
+++ b/accessible/src/xul/nsXULListboxAccessible.h
@@ -124,17 +124,18 @@ public:
   NS_IMETHOD GetActionName(PRUint8 index, nsAString& aName);
   // Don't use XUL menuitems's description attribute
   NS_IMETHOD GetDescription(nsAString& aDesc) { return nsAccessibleWrap::GetDescription(aDesc); }
 
   // nsAccessible
   virtual nsresult GetNameInternal(nsAString& aName);
   virtual nsresult GetRoleInternal(PRUint32 *aRole);
   virtual nsresult GetStateInternal(PRUint32 *aState, PRUint32 *aExtraState);
-  virtual nsresult GetAttributesInternal(nsIPersistentProperties *aAttributes);
+  virtual void GetPositionAndSizeInternal(PRInt32 *aPosInSet,
+                                          PRInt32 *aSetSize);
   virtual PRBool GetAllowsAnonChildAccessibles();
 
 protected:
   already_AddRefed<nsIAccessible> GetListAccessible();
 
 private:
   PRBool mIsCheckbox;
 };
--- a/accessible/src/xul/nsXULMenuAccessible.cpp
+++ b/accessible/src/xul/nsXULMenuAccessible.cpp
@@ -497,27 +497,28 @@ nsXULMenuitemAccessible::GetRoleInternal
   if (menuItemType.EqualsIgnoreCase("radio"))
     *aRole = nsIAccessibleRole::ROLE_RADIO_MENU_ITEM;
   else if (menuItemType.EqualsIgnoreCase("checkbox"))
     *aRole = nsIAccessibleRole::ROLE_CHECK_MENU_ITEM;
 
   return NS_OK;
 }
 
-nsresult
-nsXULMenuitemAccessible::GetAttributesInternal(nsIPersistentProperties *aAttributes)
+PRInt32
+nsXULMenuitemAccessible::GetLevelInternal()
 {
-  NS_ENSURE_ARG_POINTER(aAttributes);
-  NS_ENSURE_TRUE(mDOMNode, NS_ERROR_FAILURE);
+  return nsAccUtils::GetLevelForXULContainerItem(mDOMNode);
+}
 
-  nsresult rv = nsAccessible::GetAttributesInternal(aAttributes);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  nsAccUtils::SetAccAttrsForXULContainerItem(mDOMNode, aAttributes);
-  return NS_OK;
+void
+nsXULMenuitemAccessible::GetPositionAndSizeInternal(PRInt32 *aPosInSet,
+                                                    PRInt32 *aSetSize)
+{
+  nsAccUtils::GetPositionAndSizeForXULContainerItem(mDOMNode, aPosInSet,
+                                                    aSetSize);
 }
 
 PRBool
 nsXULMenuitemAccessible::GetAllowsAnonChildAccessibles()
 {
   // That indicates we don't walk anonymous children for menuitems
   return PR_FALSE;
 }
--- a/accessible/src/xul/nsXULMenuAccessible.h
+++ b/accessible/src/xul/nsXULMenuAccessible.h
@@ -87,17 +87,19 @@ public:
 
   // nsAccessNode
   virtual nsresult Init();
 
   // nsAccessible
   virtual nsresult GetNameInternal(nsAString& aName);
   virtual nsresult GetRoleInternal(PRUint32 *aRole);
   virtual nsresult GetStateInternal(PRUint32 *aState, PRUint32 *aExtraState);
-  virtual nsresult GetAttributesInternal(nsIPersistentProperties *aAttributes);
+  virtual PRInt32 GetLevelInternal();
+  virtual void GetPositionAndSizeInternal(PRInt32 *aPosInSet,
+                                          PRInt32 *aSetSize);
 
   virtual PRBool GetAllowsAnonChildAccessibles();
 };
 
 class nsXULMenuSeparatorAccessible : public nsXULMenuitemAccessible
 {
 public:
   nsXULMenuSeparatorAccessible(nsIDOMNode* aDomNode, nsIWeakReference* aShell);
--- a/accessible/src/xul/nsXULTabAccessible.cpp
+++ b/accessible/src/xul/nsXULTabAccessible.cpp
@@ -196,29 +196,28 @@ nsXULTabAccessible::GetRelationByType(PR
     nsCOMPtr<nsIAccessible> acc;
     childAcc->GetNextSibling(getter_AddRefs(acc));
     childAcc.swap(acc);
   }
 
   return NS_OK;
 }
 
-nsresult
-nsXULTabAccessible::GetAttributesInternal(nsIPersistentProperties *aAttributes)
+void
+nsXULTabAccessible::GetPositionAndSizeInternal(PRInt32 *aPosInSet,
+                                               PRInt32 *aSetSize)
 {
-  NS_ENSURE_ARG_POINTER(aAttributes);
-  NS_ENSURE_TRUE(mDOMNode, NS_ERROR_FAILURE);
+  nsAccUtils::GetPositionAndSizeForXULSelectControlItem(mDOMNode, aPosInSet,
+                                                        aSetSize);
+}
 
-  nsresult rv = nsLeafAccessible::GetAttributesInternal(aAttributes);
-  NS_ENSURE_SUCCESS(rv, rv);
 
-  nsAccUtils::SetAccAttrsForXULSelectControlItem(mDOMNode, aAttributes);
-
-  return NS_OK;
-}
+////////////////////////////////////////////////////////////////////////////////
+// nsXULTabBoxAccessible
+////////////////////////////////////////////////////////////////////////////////
 
 /**
   * XUL TabBox
   *  to facilitate naming of the tabPanels object we will give this the name
   *   of the selected tab in the tabs object.
   */
 
 /** Constructor */
--- a/accessible/src/xul/nsXULTabAccessible.h
+++ b/accessible/src/xul/nsXULTabAccessible.h
@@ -56,17 +56,18 @@ public:
   // nsIAccessible
   NS_IMETHOD GetNumActions(PRUint8 *_retval);
   NS_IMETHOD GetActionName(PRUint8 aIndex, nsAString& aName);
   NS_IMETHOD DoAction(PRUint8 index);
   NS_IMETHOD GetRelationByType(PRUint32 aRelationType,
                                nsIAccessibleRelation **aRelation);
 
   // nsAccessible
-  virtual nsresult GetAttributesInternal(nsIPersistentProperties *aAttributes);
+  virtual void GetPositionAndSizeInternal(PRInt32 *aPosInSet,
+                                          PRInt32 *aSetSize);
   virtual nsresult GetRoleInternal(PRUint32 *aRole);
   virtual nsresult GetStateInternal(PRUint32 *aState, PRUint32 *aExtraState);
 };
 
 /** 
   * Contains a tabs object and a tabPanels object. A complete
   *    entity with relationships between tabs and content to
   *    be displayed in the tabpanels object
--- a/accessible/src/xul/nsXULTreeAccessible.cpp
+++ b/accessible/src/xul/nsXULTreeAccessible.cpp
@@ -957,20 +957,30 @@ nsXULTreeItemAccessibleBase::Shutdown()
   mRow = -1;
 
   return nsAccessibleWrap::Shutdown();
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsXULTreeItemAccessibleBase: nsAccessible public methods
 
+// nsIAccessible::groupPosition
 nsresult
-nsXULTreeItemAccessibleBase::GetAttributesInternal(nsIPersistentProperties *aAttributes)
+nsXULTreeItemAccessibleBase::GroupPosition(PRInt32 *aGroupLevel,
+                                           PRInt32 *aSimilarItemsInGroup,
+                                           PRInt32 *aPositionInGroup)
 {
-  NS_ENSURE_ARG_POINTER(aAttributes);
+  NS_ENSURE_ARG_POINTER(aGroupLevel);
+  *aGroupLevel = 0;
+
+  NS_ENSURE_ARG_POINTER(aSimilarItemsInGroup);
+  *aSimilarItemsInGroup = 0;
+
+  NS_ENSURE_ARG_POINTER(aPositionInGroup);
+  *aPositionInGroup = 0;
 
   if (IsDefunct())
     return NS_ERROR_FAILURE;
 
   PRInt32 level;
   nsresult rv = mTreeView->GetLevel(mRow, &level);
   NS_ENSURE_SUCCESS(rv, rv);
 
@@ -1000,18 +1010,20 @@ nsXULTreeItemAccessibleBase::GetAttribut
       if (lvl == level)
         bottomCount++;
     }
   }
 
   PRInt32 setSize = topCount + bottomCount;
   PRInt32 posInSet = topCount;
 
-  // set the group attributes
-  nsAccUtils::SetAccGroupAttrs(aAttributes, level + 1, posInSet, setSize);
+  *aGroupLevel = level + 1;
+  *aSimilarItemsInGroup = setSize;
+  *aPositionInGroup = posInSet;
+
   return NS_OK;
 }
 
 nsresult
 nsXULTreeItemAccessibleBase::GetStateInternal(PRUint32 *aState,
                                               PRUint32 *aExtraState)
 {
   NS_ENSURE_ARG_POINTER(aState);
--- a/accessible/src/xul/nsXULTreeAccessible.h
+++ b/accessible/src/xul/nsXULTreeAccessible.h
@@ -182,26 +182,29 @@ public:
                        PRInt32 *aWidth, PRInt32 *aHeight);
 
   NS_IMETHOD SetSelected(PRBool aSelect); 
   NS_IMETHOD TakeFocus();
 
   NS_IMETHOD GetRelationByType(PRUint32 aRelationType,
                                nsIAccessibleRelation **aRelation);
 
+  NS_IMETHOD GroupPosition(PRInt32 *aGroupLevel,
+                           PRInt32 *aSimilarItemsInGroup,
+                           PRInt32 *aPositionInGroup);
+
   NS_IMETHOD GetNumActions(PRUint8 *aCount);
   NS_IMETHOD GetActionName(PRUint8 aIndex, nsAString& aName);
   NS_IMETHOD DoAction(PRUint8 aIndex);
 
   // nsAccessNode
   virtual PRBool IsDefunct();
   virtual nsresult Shutdown();
 
   // nsAccessible
-  virtual nsresult GetAttributesInternal(nsIPersistentProperties *aAttributes);
   virtual nsresult GetStateInternal(PRUint32 *aState, PRUint32 *aExtraState);
   virtual nsIAccessible* GetParent();
 
   // nsXULTreeItemAccessibleBase
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_XULTREEITEMBASEACCESSIBLE_IMPL_CID)
 
   /**
    * Return row index associated with the accessible.
--- a/accessible/tests/mochitest/attributes.js
+++ b/accessible/tests/mochitest/attributes.js
@@ -23,34 +23,50 @@ function testAttrs(aAccOrElmOrID, aAttrs
  *                              present (name/value pairs)
  */
 function testAbsentAttrs(aAccOrElmOrID, aAbsentAttrs)
 {
   testAttrsInternal(aAccOrElmOrID, {}, true, aAbsentAttrs);
 }
 
 /**
- * Test group object attributes (posinset, setsize and level)
+ * Test group object attributes (posinset, setsize and level) and
+ * nsIAccessible::groupPosition() method.
  *
  * @param aAccOrElmOrID  [in] the ID, DOM node or accessible
  * @param aPosInSet      [in] the value of 'posinset' attribute
  * @param aSetSize       [in] the value of 'setsize' attribute
  * @param aLevel         [in, optional] the value of 'level' attribute
  */
 function testGroupAttrs(aAccOrElmOrID, aPosInSet, aSetSize, aLevel)
 {
-  var attrs = {
-    "posinset": String(aPosInSet),
-    "setsize": String(aSetSize)
-  };
+  var acc = getAccessible(aAccOrElmOrID);
+  var levelObj = {}, posInSetObj = {}, setSizeObj = {};
+  acc.groupPosition(levelObj, setSizeObj, posInSetObj);
+
+  if (aPosInSet && aSetSize) {
+    is(posInSetObj.value, aPosInSet,
+       "Wrong group position (posinset) for " + prettyName(aAccOrElmOrID));
+    is(setSizeObj.value, aSetSize,
+       "Wrong size of the group (setsize) for " + prettyName(aAccOrElmOrID));
 
-  if (aLevel)
-    attrs["level"] = String(aLevel);
+    var attrs = {
+      "posinset": String(aPosInSet),
+      "setsize": String(aSetSize)
+    };
+    testAttrs(aAccOrElmOrID, attrs, true);
+  }
 
-  testAttrs(aAccOrElmOrID, attrs, true);
+  if (aLevel) {
+    is(levelObj.value, aLevel,
+       "Wrong group level for " + prettyName(aAccOrElmOrID));
+
+    var attrs = { "level" : String(aLevel) };
+    testAttrs(aAccOrElmOrID, attrs, true);
+  }
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // Text attributes.
 
 /**
  * Test text attributes.
  *
--- a/accessible/tests/mochitest/attributes/test_obj_group.html
+++ b/accessible/tests/mochitest/attributes/test_obj_group.html
@@ -19,16 +19,35 @@
     function doTest()
     {
       //////////////////////////////////////////////////////////////////////////
       // HTML select
       testGroupAttrs("opt1", 1, 2);
       testGroupAttrs("opt2", 2, 2);
 
       //////////////////////////////////////////////////////////////////////////
+      // HTML select with options
+      // XXX bug 469123
+      //testGroupAttrs("select2_optgroup", 1, 3, 1);
+      //testGroupAttrs("select2_opt3", 2, 3, 1);
+      //testGroupAttrs("select2_opt4", 3, 3, 1);
+      //testGroupAttrs("select2_opt1", 1, 2, 2);
+      //testGroupAttrs("select2_opt2", 2, 2, 2);
+
+      //////////////////////////////////////////////////////////////////////////
+      // HTML input@type="radio" within form
+      testGroupAttrs("radio1", 1, 2);
+      testGroupAttrs("radio2", 2, 2);
+
+      //////////////////////////////////////////////////////////////////////////
+      // HTML input@type="radio" within document
+      testGroupAttrs("radio3", 1, 2);
+      testGroupAttrs("radio4", 2, 2);
+
+      //////////////////////////////////////////////////////////////////////////
       // HTML ul/ol
       testGroupAttrs("li1", 1, 3);
       testGroupAttrs("li2", 2, 3);
       testGroupAttrs("li3", 3, 3);
 
       //////////////////////////////////////////////////////////////////////////
       // HTML ul/ol (nested lists)
 
@@ -52,16 +71,38 @@
       testGroupAttrs("li11", 2, 3, 1);
       testGroupAttrs("li12", 3, 3, 1);
 
       testGroupAttrs("n_li10", 1, 3, 2);
       testGroupAttrs("n_li11", 2, 3, 2);
       testGroupAttrs("n_li12", 3, 3, 2);
 
       //////////////////////////////////////////////////////////////////////////
+      // ARIA menu (menuitem, separator, menuitemradio and menuitemcheckbox)
+      testGroupAttrs("menu_item1", 1, 2);
+      testGroupAttrs("menu_item2", 2, 2);
+      testGroupAttrs("menu_item1.1", 1, 2);
+      testGroupAttrs("menu_item1.2", 2, 2);
+      testGroupAttrs("menu_item1.3", 1, 3);
+      testGroupAttrs("menu_item1.4", 2, 3);
+      testGroupAttrs("menu_item1.5", 3, 3);
+
+      //////////////////////////////////////////////////////////////////////////
+      // ARIA tab
+      testGroupAttrs("tab_1", 1, 3);
+      testGroupAttrs("tab_2", 2, 3);
+      testGroupAttrs("tab_3", 3, 3);
+
+      //////////////////////////////////////////////////////////////////////////
+      // ARIA radio
+      testGroupAttrs("r1", 1, 3);
+      testGroupAttrs("r2", 2, 3);
+      testGroupAttrs("r3", 3, 3);
+
+      //////////////////////////////////////////////////////////////////////////
       // ARIA grid
       testGroupAttrs("grid_row1", 1, 2);
       testGroupAttrs("grid_cell1", 1, 2);
       testGroupAttrs("grid_cell2", 2, 2);
 
       testGroupAttrs("grid_row2", 2, 2);
       testGroupAttrs("grid_cell3", 1, 2);
       testGroupAttrs("grid_cell4", 2, 2);
@@ -75,16 +116,25 @@
       testGroupAttrs("treegrid_row2", 2, 3, 2);
       testGroupAttrs("treegrid_cell3", 1, 2);
       testGroupAttrs("treegrid_cell4", 2, 2);
 
       testGroupAttrs("treegrid_row3", 3, 3, 1);
       testGroupAttrs("treegrid_cell5", 1, 2);
       testGroupAttrs("treegrid_cell6", 2, 2);
 
+      //////////////////////////////////////////////////////////////////////////
+      // HTML headings
+      testGroupAttrs("h1", 0, 0, 1);
+      testGroupAttrs("h2", 0, 0, 2);
+      testGroupAttrs("h3", 0, 0, 3);
+      testGroupAttrs("h4", 0, 0, 4);
+      testGroupAttrs("h5", 0, 0, 5);
+      testGroupAttrs("h6", 0, 0, 6);
+
       SimpleTest.finish();
     }
 
     SimpleTest.waitForExplicitFinish();
     addA11yLoadEvent(doTest);
   </script>
 </head>
 <body>
@@ -100,16 +150,33 @@
   <pre id="test">
   </pre>
 
   <select size="4">
     <option id="opt1">option1</option>
     <option id="opt2">option2</option>
   </select>
 
+  <select size="4">
+    <optgroup id="select2_optgroup" label="group">
+      <option id="select2_opt1">option1</option>
+      <option id="select2_opt2">option2</option>
+    </optgroup>
+    <option id="select2_opt3">option3</option>
+    <option id="select2_opt4">option4</option>
+  </select>
+
+  <form>
+    <input type="radio" id="radio1" name="group1"/>
+    <input type="radio" id="radio2" name="group1"/>
+  </form>
+
+  <input type="radio" id="radio3" name="group2"/>
+  <input type="radio" id="radio4" name="group2"/>
+
   <ul>
     <li id="li1">Oranges</li>
     <li id="li2">Apples</li>
     <li id="li3">Bananas</li>
   </ul>
 
   <ol>
     <li id="li4">Oranges</li>
@@ -136,16 +203,42 @@
       <span role="list">
         <span role="listitem" id="n_li10">Oranges</span>
         <span role="listitem" id="n_li11">Apples</span>
         <span role="listitem" id="n_li12">Bananas</span>
       </span>
     </span>
   </span>
 
+  <ul role="menubar">
+    <li role="menuitem" aria-haspopup="true" id="menu_item1">File
+      <ul role="menu">
+        <li role="menuitem" id="menu_item1.1">New</li>
+        <li role="menuitem" id="menu_item1.2">Open…</li>
+        <li role="separator">-----</li>
+        <li role="menuitem" id="menu_item1.3">Item</li>
+        <li role="menuitemradio" id="menu_item1.4">Radio</li>
+        <li role="menuitemcheckbox" id="menu_item1.5">Checkbox</li>
+      </ul>
+    </li>
+    <li role="menuitem" aria-haspopup="false" id="menu_item2">Help</li>
+  </ul>
+
+  <ul id="tablist_1" role="tablist">
+    <li id="tab_1" role="tab">Crust</li>
+    <li id="tab_2" role="tab">Veges</li>
+    <li id="tab_3" role="tab">Carnivore</li>
+  </ul>
+
+  <ul id="rg1" role="radiogroup">
+    <li id="r1" role="radio" aria-checked="false">Thai</li>
+    <li id="r2" role="radio" aria-checked="false">Subway</li>
+    <li id="r3" role="radio" aria-checked="false">Jimmy Johns</li>
+  </ul>
+
   <table role="grid">
     <tr role="row" id="grid_row1">
       <td role="gridcell" id="grid_cell1">cell1</td>
       <td role="gridcell" id="grid_cell2">cell2</td>
     </tr>
     <tr role="row" id="grid_row2">
       <td role="gridcell" id="grid_cell3">cell3</td>
       <td role="gridcell" id="grid_cell4">cell4</td>
@@ -161,10 +254,18 @@
       <div role="gridcell" id="treegrid_cell3">cell1</div>
       <div role="gridcell" id="treegrid_cell4">cell2</div>
     </div>
     <div role="row" id="treegrid_row3">
       <div role="gridcell" id="treegrid_cell5">cell1</div>
       <div role="gridcell" id="treegrid_cell6">cell2</div>
     </div>
   </div>
+
+  <h1 id="h1">heading1</h1>
+  <h2 id="h2">heading2</h2>
+  <h3 id="h3">heading3</h3>
+  <h4 id="h4">heading4</h4>
+  <h5 id="h5">heading5</h5>
+  <h6 id="h6">heading6</h6>
+
 </body>
 </html>
--- a/accessible/tests/mochitest/attributes/test_obj_group.xul
+++ b/accessible/tests/mochitest/attributes/test_obj_group.xul
@@ -17,46 +17,56 @@
           src="chrome://mochikit/content/a11y/accessible/attributes.js" />
 
   <script type="application/javascript">
   <![CDATA[
     function doTest()
     {
       //////////////////////////////////////////////////////////////////////////
       // xul:listbox (bug 417317)
-      testGroupAttrs("item1", "1", "2");
-      testGroupAttrs("item2", "2", "2");
+      testGroupAttrs("item1", 1, 2);
+      testGroupAttrs("item2", 2, 2);
 
       //////////////////////////////////////////////////////////////////////////
       // xul:menu (bug 443881)
       var menu1 = document.getElementById("menu_item1");
       menu1.open = true;
 
       window.setTimeout(function() {
         var menu2 = document.getElementById("menu_item2");
         menu2.open = true;
 
         window.setTimeout(function() {
-          testGroupAttrs("menu_item1.1", "1", "1");
-          testGroupAttrs("menu_item1.2", "1", "3");
-          testGroupAttrs("menu_item1.4", "2", "3");
-          testGroupAttrs("menu_item2", "3", "3");
-          testGroupAttrs("menu_item2.1", "1", "2", "1");
-          testGroupAttrs("menu_item2.2", "2", "2", "1");
+          testGroupAttrs("menu_item1.1", 1, 1);
+          testGroupAttrs("menu_item1.2", 1, 3);
+          testGroupAttrs("menu_item1.4", 2, 3);
+          testGroupAttrs("menu_item2", 3, 3);
+          testGroupAttrs("menu_item2.1", 1, 2, 1);
+          testGroupAttrs("menu_item2.2", 2, 2, 1);
 
           SimpleTest.finish();
         }, 200);
       }, 200);
 
       //////////////////////////////////////////////////////////////////////////
+      // xul:tab
+      testGroupAttrs("tab1", 1, 2);
+      testGroupAttrs("tab2", 2, 2);
+
+      //////////////////////////////////////////////////////////////////////////
+      // xul:radio
+      testGroupAttrs("radio1", 1, 2);
+      testGroupAttrs("radio2", 2, 2);
+
+      //////////////////////////////////////////////////////////////////////////
       // ARIA menu (bug 441888)
-      testGroupAttrs("aria-menuitem", "1", "3");
-      testGroupAttrs("aria-menuitemcheckbox", "2", "3");
-      testGroupAttrs("aria-menuitemradio", "3", "3");
-      testGroupAttrs("aria-menuitem2", "1", "1");
+      testGroupAttrs("aria-menuitem", 1, 3);
+      testGroupAttrs("aria-menuitemcheckbox", 2, 3);
+      testGroupAttrs("aria-menuitemradio", 3, 3);
+      testGroupAttrs("aria-menuitem2", 1, 1);
     }
 
     SimpleTest.waitForExplicitFinish();
     addA11yLoadEvent(doTest);
   ]]>
   </script>
 
   <body xmlns="http://www.w3.org/1999/xhtml">
@@ -101,16 +111,32 @@
             <menuitem label="item2.1" id="menu_item2.1"/>
             <menuitem label="item2.2" id="menu_item2.2"/>
           </menupopup>
         </menu>
       </menupopup>
     </menu>
   </menubar>
 
+  <tabbox>
+    <tabs>
+      <tab id="tab1" label="tab1"/>
+      <tab id="tab2" label="tab3"/>
+    </tabs>
+    <tabpanels>
+      <tabpanel/>
+      <tabpanel/>
+    </tabpanels>
+  </tabbox>
+
+  <radiogroup>
+    <radio id="radio1" label="radio1"/>
+    <radio id="radio2" label="radio2"/>
+  </radiogroup>
+
   <vbox>
     <description role="menuitem" id="aria-menuitem"
                  value="conventional menuitem"/>
     <description role="menuitemcheckbox" id="aria-menuitemcheckbox"
                  value="conventional checkbox menuitem"/>
     <description role="menuitem" hidden="true"/>
     <description role="menuitemradio" id="aria-menuitemradio"
                  value="conventional radio menuitem"/>
--- a/accessible/tests/mochitest/attributes/test_obj_group_tree.xul
+++ b/accessible/tests/mochitest/attributes/test_obj_group_tree.xul
@@ -26,32 +26,32 @@
 
     function doTestAttrs()
     {
       var treeNode = getNode("tree");
       treeNode.removeEventListener("TreeViewChanged", doTestAttrs, false);
 
       var tree = getAccessible(treeNode);
       var treeitem1 = tree.firstChild.nextSibling;
-      testGroupAttrs(treeitem1, "1", "4", "1");
+      testGroupAttrs(treeitem1, 1, 4, 1);
 
       var treeitem2 = treeitem1.nextSibling;
-      testGroupAttrs(treeitem2, "2", "4", "1");
+      testGroupAttrs(treeitem2, 2, 4, 1);
 
       var treeitem3 = treeitem2.nextSibling;
-      testGroupAttrs(treeitem3, "1", "2", "2");
+      testGroupAttrs(treeitem3, 1, 2, 2);
 
       var treeitem4 = treeitem3.nextSibling;
-      testGroupAttrs(treeitem4, "2", "2", "2");
+      testGroupAttrs(treeitem4, 2, 2, 2);
 
       var treeitem5 = treeitem4.nextSibling;
-      testGroupAttrs(treeitem5, "3", "4", "1");
+      testGroupAttrs(treeitem5, 3, 4, 1);
 
       var treeitem6 = treeitem5.nextSibling;
-      testGroupAttrs(treeitem6, "4", "4", "1");
+      testGroupAttrs(treeitem6, 4, 4, 1);
 
       SimpleTest.finish();
     }
 
     function doTest()
     {
       var treeNode = getNode("tree");
       treeNode.addEventListener("TreeViewChanged", doTestAttrs, false);