Bug 590176 - add pseudo SelectAccessible interface, r=marcoz, davidb, a=davidb
authorAlexander Surkov <surkov.alexander@gmail.com>
Thu, 02 Sep 2010 09:46:59 +0900
changeset 51865 cbbccc115e555e4cc0b7aacd6c70b21131df87f7
parent 51864 3c3c95c37d204897dfef2e050368f2117ea9b097
child 51866 d81c3c24a14bca073c91f719132a0000d3468a9f
push id15455
push usersurkov.alexander@gmail.com
push dateThu, 02 Sep 2010 00:48:16 +0000
treeherdermozilla-central@cbbccc115e55 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmarcoz, davidb, davidb
bugs590176
milestone2.0b6pre
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 590176 - add pseudo SelectAccessible interface, r=marcoz, davidb, a=davidb
accessible/src/atk/nsAccessibleWrap.cpp
accessible/src/atk/nsMaiInterfaceSelection.cpp
accessible/src/atk/nsMaiInterfaceSelection.h
accessible/src/base/nsAccUtils.cpp
accessible/src/base/nsAccessible.cpp
accessible/src/base/nsAccessible.h
accessible/src/base/nsDocAccessible.cpp
accessible/src/html/nsHTMLSelectAccessible.cpp
accessible/src/html/nsHTMLSelectAccessible.h
accessible/src/msaa/nsAccessibleWrap.cpp
accessible/src/xforms/nsXFormsAccessible.cpp
accessible/src/xforms/nsXFormsAccessible.h
accessible/src/xul/nsXULListboxAccessible.cpp
accessible/src/xul/nsXULMenuAccessible.cpp
accessible/src/xul/nsXULMenuAccessible.h
accessible/src/xul/nsXULTreeAccessible.cpp
accessible/src/xul/nsXULTreeAccessible.h
accessible/tests/mochitest/selectable.js
accessible/tests/mochitest/selectable/Makefile.in
accessible/tests/mochitest/selectable/test_aria.html
accessible/tests/mochitest/selectable/test_listbox.xul
accessible/tests/mochitest/selectable/test_menu.xul
accessible/tests/mochitest/selectable/test_menulist.xul
accessible/tests/mochitest/selectable/test_select.html
--- a/accessible/src/atk/nsAccessibleWrap.cpp
+++ b/accessible/src/atk/nsAccessibleWrap.cpp
@@ -470,20 +470,17 @@ nsAccessibleWrap::CreateMaiInterfaces(vo
       nsCOMPtr<nsIAccessibleTable> accessInterfaceTable;
       QueryInterface(NS_GET_IID(nsIAccessibleTable),
                      getter_AddRefs(accessInterfaceTable));
       if (accessInterfaceTable) {
           interfacesBits |= 1 << MAI_INTERFACE_TABLE;
       }
       
       //nsIAccessibleSelection
-      nsCOMPtr<nsIAccessibleSelectable> accessInterfaceSelection;
-      QueryInterface(NS_GET_IID(nsIAccessibleSelectable),
-                     getter_AddRefs(accessInterfaceSelection));
-      if (accessInterfaceSelection) {
+      if (IsSelect()) {
           interfacesBits |= 1 << MAI_INTERFACE_SELECTION;
       }
     }
 
     return interfacesBits;
 }
 
 static GType
--- a/accessible/src/atk/nsMaiInterfaceSelection.cpp
+++ b/accessible/src/atk/nsMaiInterfaceSelection.cpp
@@ -55,125 +55,81 @@ selectionInterfaceInitCB(AtkSelectionIfa
     aIface->remove_selection = removeSelectionCB;
     aIface->select_all_selection = selectAllSelectionCB;
 }
 
 gboolean
 addSelectionCB(AtkSelection *aSelection, gint i)
 {
     nsAccessibleWrap *accWrap = GetAccessibleWrap(ATK_OBJECT(aSelection));
-    if (!accWrap)
+    if (!accWrap || !accWrap->IsSelect())
         return FALSE;
 
-    nsCOMPtr<nsIAccessibleSelectable> accSelection;
-    accWrap->QueryInterface(NS_GET_IID(nsIAccessibleSelectable),
-                            getter_AddRefs(accSelection));
-    NS_ENSURE_TRUE(accSelection, FALSE);
-
-    return NS_SUCCEEDED(accSelection->AddChildToSelection(i));
+    return accWrap->AddItemToSelection(i);
 }
 
 gboolean
 clearSelectionCB(AtkSelection *aSelection)
 {
     nsAccessibleWrap *accWrap = GetAccessibleWrap(ATK_OBJECT(aSelection));
-    if (!accWrap)
+    if (!accWrap || !accWrap->IsSelect())
         return FALSE;
 
-    nsCOMPtr<nsIAccessibleSelectable> accSelection;
-    accWrap->QueryInterface(NS_GET_IID(nsIAccessibleSelectable),
-                            getter_AddRefs(accSelection));
-    NS_ENSURE_TRUE(accSelection, FALSE);
-
-    return NS_SUCCEEDED(accSelection->ClearSelection());
+    return accWrap->UnselectAll();
 }
 
 AtkObject *
 refSelectionCB(AtkSelection *aSelection, gint i)
 {
     nsAccessibleWrap *accWrap = GetAccessibleWrap(ATK_OBJECT(aSelection));
-    if (!accWrap)
+    if (!accWrap || !accWrap->IsSelect())
         return nsnull;
 
-    nsCOMPtr<nsIAccessibleSelectable> accSelection;
-    accWrap->QueryInterface(NS_GET_IID(nsIAccessibleSelectable),
-                            getter_AddRefs(accSelection));
-    NS_ENSURE_TRUE(accSelection, nsnull);
+    nsAccessible* selectedItem = accWrap->GetSelectedItem(i);
+    if (!selectedItem)
+        return nsnull;
 
-    nsCOMPtr<nsIAccessible> accSelect;
-    accSelection->RefSelection(i, getter_AddRefs(accSelect));
-    if (!accSelect) {
-        return nsnull;
-    }
-
-    AtkObject *atkObj = nsAccessibleWrap::GetAtkObject(accSelect);
+    AtkObject* atkObj = nsAccessibleWrap::GetAtkObject(selectedItem);
     if (atkObj) {
         g_object_ref(atkObj);
     }
     return atkObj;
 }
 
 gint
 getSelectionCountCB(AtkSelection *aSelection)
 {
     nsAccessibleWrap *accWrap = GetAccessibleWrap(ATK_OBJECT(aSelection));
-    if (!accWrap)
+    if (!accWrap || !accWrap->IsSelect())
         return -1;
 
-    nsCOMPtr<nsIAccessibleSelectable> accSelection;
-    accWrap->QueryInterface(NS_GET_IID(nsIAccessibleSelectable),
-                            getter_AddRefs(accSelection));
-    NS_ENSURE_TRUE(accSelection, -1);
-
-    PRInt32 num = 0;
-    nsresult rv = accSelection->GetSelectionCount(&num);
-    return (NS_FAILED(rv)) ? -1 : num;
+    return accWrap->SelectedItemCount();
 }
 
 gboolean
 isChildSelectedCB(AtkSelection *aSelection, gint i)
 {
     nsAccessibleWrap *accWrap = GetAccessibleWrap(ATK_OBJECT(aSelection));
-    if (!accWrap)
+    if (!accWrap || !accWrap->IsSelect())
         return FALSE;
 
-    nsCOMPtr<nsIAccessibleSelectable> accSelection;
-    accWrap->QueryInterface(NS_GET_IID(nsIAccessibleSelectable),
-                            getter_AddRefs(accSelection));
-    NS_ENSURE_TRUE(accSelection, FALSE);
-
-    PRBool result = FALSE;
-    nsresult rv = accSelection->IsChildSelected(i, &result);
-    return (NS_FAILED(rv)) ? FALSE : result;
+    return accWrap->IsItemSelected(i);
 }
 
 gboolean
 removeSelectionCB(AtkSelection *aSelection, gint i)
 {
     nsAccessibleWrap *accWrap = GetAccessibleWrap(ATK_OBJECT(aSelection));
-    if (!accWrap)
+    if (!accWrap || !accWrap->IsSelect())
         return FALSE;
 
-    nsCOMPtr<nsIAccessibleSelectable> accSelection;
-    accWrap->QueryInterface(NS_GET_IID(nsIAccessibleSelectable),
-                            getter_AddRefs(accSelection));
-    NS_ENSURE_TRUE(accSelection, FALSE);
-
-    nsresult rv = accSelection->RemoveChildFromSelection(i);
-    return (NS_FAILED(rv)) ? FALSE : TRUE;
+    return accWrap->RemoveItemFromSelection(i);
 }
 
 gboolean
 selectAllSelectionCB(AtkSelection *aSelection)
 {
     nsAccessibleWrap *accWrap = GetAccessibleWrap(ATK_OBJECT(aSelection));
-    if (!accWrap)
+    if (!accWrap || !accWrap->IsSelect())
         return FALSE;
 
-    nsCOMPtr<nsIAccessibleSelectable> accSelection;
-    accWrap->QueryInterface(NS_GET_IID(nsIAccessibleSelectable),
-                            getter_AddRefs(accSelection));
-    NS_ENSURE_TRUE(accSelection, FALSE);
-
-    PRBool result = FALSE;
-    nsresult rv = accSelection->SelectAllSelection(&result);
-    return (NS_FAILED(rv)) ? FALSE : result;
+    return accWrap->SelectAll();
 }
--- a/accessible/src/atk/nsMaiInterfaceSelection.h
+++ b/accessible/src/atk/nsMaiInterfaceSelection.h
@@ -37,17 +37,16 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef __MAI_INTERFACE_SELECTION_H__
 #define __MAI_INTERFACE_SELECTION_H__
 
 #include "nsMai.h"
-#include "nsIAccessibleSelectable.h"
 
 G_BEGIN_DECLS
 
 /* selection interface callbacks */
 
 void selectionInterfaceInitCB(AtkSelectionIface *aIface);
 gboolean addSelectionCB(AtkSelection *aSelection, gint i);
 gboolean clearSelectionCB(AtkSelection *aSelection);
--- a/accessible/src/base/nsAccUtils.cpp
+++ b/accessible/src/base/nsAccUtils.cpp
@@ -371,26 +371,21 @@ nsAccessible *
 nsAccUtils::GetSelectableContainer(nsAccessible *aAccessible, PRUint32 aState)
 {
   if (!aAccessible)
     return nsnull;
 
   if (!(aState & nsIAccessibleStates::STATE_SELECTABLE))
     return nsnull;
 
-  nsCOMPtr<nsIAccessibleSelectable> container;
-  nsAccessible *parent = aAccessible;
-  while (!container) {
-    parent = parent->GetParent();
-    if (!parent || Role(parent) == nsIAccessibleRole::ROLE_PANE)
+  nsAccessible* parent = aAccessible;
+  while ((parent = parent->GetParent()) && !parent->IsSelect()) {
+    if (Role(parent) == nsIAccessibleRole::ROLE_PANE)
       return nsnull;
-
-    container = do_QueryObject(parent);
   }
-
   return parent;
 }
 
 nsAccessible *
 nsAccUtils::GetMultiSelectableContainer(nsINode *aNode)
 {
   nsAccessible *accessible = GetAccService()->GetAccessible(aNode);
   nsAccessible *container = GetSelectableContainer(accessible,
--- a/accessible/src/base/nsAccessible.cpp
+++ b/accessible/src/base/nsAccessible.cpp
@@ -150,30 +150,22 @@ nsresult nsAccessible::QueryInterface(RE
 
   if (aIID.Equals(NS_GET_IID(nsAccessible))) {
     *aInstancePtr = static_cast<nsAccessible*>(this);
     NS_ADDREF_THIS();
     return NS_OK;
   }
 
   if (aIID.Equals(NS_GET_IID(nsIAccessibleSelectable))) {
-    if (mRoleMapEntry &&
-        (mRoleMapEntry->attributeMap1 == eARIAMultiSelectable ||
-         mRoleMapEntry->attributeMap2 == eARIAMultiSelectable ||
-         mRoleMapEntry->attributeMap3 == eARIAMultiSelectable)) {
-
-      // If we have an ARIA role attribute present and the role allows multi
-      // selectable state, then we need to support nsIAccessibleSelectable.
-      // If either attribute (role or multiselectable) change, then we'll
-      // destroy this accessible so that we can follow COM identity rules.
-
+    if (IsSelect()) {
       *aInstancePtr = static_cast<nsIAccessibleSelectable*>(this);
       NS_ADDREF_THIS();
       return NS_OK;
     }
+    return NS_ERROR_NO_INTERFACE;
   }
 
   if (aIID.Equals(NS_GET_IID(nsIAccessibleValue))) {
     if (mRoleMapEntry && mRoleMapEntry->valueRule != eNoValue) {
       *aInstancePtr = static_cast<nsIAccessibleValue*>(this);
       NS_ADDREF_THIS();
       return NS_OK;
     }
@@ -2376,144 +2368,119 @@ nsAccessible::DispatchClickEvent(nsICont
     return;
 
   nsCoreUtils::DispatchMouseEvent(NS_MOUSE_BUTTON_UP, presShell, aContent);
 }
 
 // nsIAccessibleSelectable
 NS_IMETHODIMP nsAccessible::GetSelectedChildren(nsIArray **aSelectedAccessibles)
 {
+  NS_ENSURE_ARG_POINTER(aSelectedAccessibles);
   *aSelectedAccessibles = nsnull;
 
-  nsCOMPtr<nsIMutableArray> selectedAccessibles =
-    do_CreateInstance(NS_ARRAY_CONTRACTID);
-  NS_ENSURE_STATE(selectedAccessibles);
-
-  AccIterator iter(this, filters::GetSelected, AccIterator::eTreeNav);
-  nsIAccessible *selected = nsnull;
-  while ((selected = iter.GetNext()))
-    selectedAccessibles->AppendElement(selected, PR_FALSE);
-
-  PRUint32 length = 0;
-  selectedAccessibles->GetLength(&length); 
-  if (length) { // length of nsIArray containing selected options
-    *aSelectedAccessibles = selectedAccessibles;
-    NS_ADDREF(*aSelectedAccessibles);
+  if (IsDefunct() || !IsSelect())
+    return NS_ERROR_FAILURE;
+
+  nsCOMPtr<nsIArray> items = SelectedItems();
+  if (items) {
+    PRUint32 length = 0;
+    items->GetLength(&length);
+    if (length)
+      items.swap(*aSelectedAccessibles);
   }
 
   return NS_OK;
 }
 
 // return the nth selected descendant nsIAccessible object
 NS_IMETHODIMP nsAccessible::RefSelection(PRInt32 aIndex, nsIAccessible **aSelected)
 {
   NS_ENSURE_ARG_POINTER(aSelected);
   *aSelected = nsnull;
 
+  if (IsDefunct() || !IsSelect())
+    return NS_ERROR_FAILURE;
+
   if (aIndex < 0) {
     return NS_ERROR_INVALID_ARG;
   }
 
-  AccIterator iter(this, filters::GetSelected, AccIterator::eTreeNav);
-  nsAccessible *selected = nsnull;
-
-  PRInt32 count = 0;
-  while (count ++ <= aIndex) {
-    selected = iter.GetNext();
-    if (!selected) {
-      // The index is out of range.
-      return NS_ERROR_INVALID_ARG;
-    }
+  *aSelected = GetSelectedItem(aIndex);
+  if (*aSelected) {
+    NS_ADDREF(*aSelected);
+    return NS_OK;
   }
-  NS_IF_ADDREF(*aSelected = selected);
-  return NS_OK;
+
+  return NS_ERROR_INVALID_ARG;
 }
 
 NS_IMETHODIMP nsAccessible::GetSelectionCount(PRInt32 *aSelectionCount)
 {
   NS_ENSURE_ARG_POINTER(aSelectionCount);
   *aSelectionCount = 0;
 
-  AccIterator iter(this, filters::GetSelected, AccIterator::eTreeNav);
-  nsAccessible *selected = nsnull;
-  while ((selected = iter.GetNext()))
-    ++(*aSelectionCount);
-
+  if (IsDefunct() || !IsSelect())
+    return NS_ERROR_FAILURE;
+
+  *aSelectionCount = SelectedItemCount();
   return NS_OK;
 }
 
 NS_IMETHODIMP nsAccessible::AddChildToSelection(PRInt32 aIndex)
 {
-  // Tree views and other container widgets which may have grandchildren should
-  // implement a selection methods for their specific interfaces, because being
-  // able to deal with selection on a per-child basis would not be enough.
-
-  NS_ENSURE_TRUE(aIndex >= 0, NS_ERROR_FAILURE);
-
-  nsAccessible* child = GetChildAt(aIndex);
-  PRUint32 state = nsAccUtils::State(child);
-  if (!(state & nsIAccessibleStates::STATE_SELECTABLE)) {
-    return NS_OK;
-  }
-
-  return child->SetSelected(PR_TRUE);
+  if (IsDefunct() || !IsSelect())
+    return NS_ERROR_FAILURE;
+
+  return aIndex >= 0 && AddItemToSelection(aIndex) ?
+    NS_OK : NS_ERROR_INVALID_ARG;
 }
 
 NS_IMETHODIMP nsAccessible::RemoveChildFromSelection(PRInt32 aIndex)
 {
-  // Tree views and other container widgets which may have grandchildren should
-  // implement a selection methods for their specific interfaces, because being
-  // able to deal with selection on a per-child basis would not be enough.
-
-  NS_ENSURE_TRUE(aIndex >= 0, NS_ERROR_FAILURE);
-
-  nsAccessible* child = GetChildAt(aIndex);
-  PRUint32 state = nsAccUtils::State(child);
-  if (!(state & nsIAccessibleStates::STATE_SELECTED)) {
-    return NS_OK;
-  }
-
-  return child->SetSelected(PR_FALSE);
+  if (IsDefunct() || !IsSelect())
+    return NS_ERROR_FAILURE;
+
+  return aIndex >=0 && RemoveItemFromSelection(aIndex) ?
+    NS_OK : NS_ERROR_INVALID_ARG;
 }
 
 NS_IMETHODIMP nsAccessible::IsChildSelected(PRInt32 aIndex, PRBool *aIsSelected)
 {
-  // Tree views and other container widgets which may have grandchildren should
-  // implement a selection methods for their specific interfaces, because being
-  // able to deal with selection on a per-child basis would not be enough.
-
+  NS_ENSURE_ARG_POINTER(aIsSelected);
   *aIsSelected = PR_FALSE;
+
+  if (IsDefunct() || !IsSelect())
+    return NS_ERROR_FAILURE;
+
   NS_ENSURE_TRUE(aIndex >= 0, NS_ERROR_FAILURE);
 
-  nsAccessible* child = GetChildAt(aIndex);
-  PRUint32 state = nsAccUtils::State(child);
-  if (state & nsIAccessibleStates::STATE_SELECTED) {
-    *aIsSelected = PR_TRUE;
-  }
+  *aIsSelected = IsItemSelected(aIndex);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsAccessible::ClearSelection()
 {
-  AccIterator iter(this, filters::GetSelected, AccIterator::eTreeNav);
-  nsAccessible *selected = nsnull;
-  while ((selected = iter.GetNext()))
-    selected->SetSelected(PR_FALSE);
-
+  if (IsDefunct() || !IsSelect())
+    return NS_ERROR_FAILURE;
+
+  UnselectAll();
   return NS_OK;
 }
 
-NS_IMETHODIMP nsAccessible::SelectAllSelection(PRBool *_retval)
+NS_IMETHODIMP
+nsAccessible::SelectAllSelection(PRBool* aIsMultiSelect)
 {
-  AccIterator iter(this, filters::GetSelectable, AccIterator::eTreeNav);
-  nsAccessible *selectable = nsnull;
-  while((selectable = iter.GetNext()))
-    selectable->SetSelected(PR_TRUE);
-
+  NS_ENSURE_ARG_POINTER(aIsMultiSelect);
+  *aIsMultiSelect = PR_FALSE;
+
+  if (IsDefunct() || !IsSelect())
+    return NS_ERROR_FAILURE;
+
+  *aIsMultiSelect = SelectAll();
   return NS_OK;
 }
 
 // nsIAccessibleHyperLink
 // Because of new-atk design, any embedded object in text can implement
 // nsIAccessibleHyperLink, which helps determine where it is located
 // within containing text
 
@@ -3028,16 +2995,148 @@ nsAccessible::GetAnchorURI(PRUint32 aAnc
               document ? document->GetDocumentCharacterSet().get() : nsnull,
               baseURI);
     return anchorURI;
   }
 
   return nsnull;
 }
 
+
+////////////////////////////////////////////////////////////////////////////////
+// SelectAccessible
+
+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);
+}
+
+already_AddRefed<nsIArray>
+nsAccessible::SelectedItems()
+{
+  nsCOMPtr<nsIMutableArray> selectedItems = do_CreateInstance(NS_ARRAY_CONTRACTID);
+  if (!selectedItems)
+    return nsnull;
+
+  AccIterator iter(this, filters::GetSelected, AccIterator::eTreeNav);
+  nsIAccessible* selected = nsnull;
+  while ((selected = iter.GetNext()))
+    selectedItems->AppendElement(selected, PR_FALSE);
+
+  nsIMutableArray* items = nsnull;
+  selectedItems.forget(&items);
+  return items;
+}
+
+PRUint32
+nsAccessible::SelectedItemCount()
+{
+  PRUint32 count = 0;
+  AccIterator iter(this, filters::GetSelected, AccIterator::eTreeNav);
+  nsAccessible* selected = nsnull;
+  while ((selected = iter.GetNext()))
+    ++count;
+
+  return count;
+}
+
+nsAccessible*
+nsAccessible::GetSelectedItem(PRUint32 aIndex)
+{
+  AccIterator iter(this, filters::GetSelected, AccIterator::eTreeNav);
+  nsAccessible* selected = nsnull;
+
+  PRUint32 index = 0;
+  while ((selected = iter.GetNext()) && index < aIndex)
+    index++;
+
+  return selected;
+}
+
+bool
+nsAccessible::IsItemSelected(PRUint32 aIndex)
+{
+  PRUint32 index = 0;
+  AccIterator iter(this, filters::GetSelectable, AccIterator::eTreeNav);
+  nsAccessible* selected = nsnull;
+  while ((selected = iter.GetNext()) && index < aIndex)
+    index++;
+
+  return selected &&
+    nsAccUtils::State(selected) & nsIAccessibleStates::STATE_SELECTED;
+}
+
+bool
+nsAccessible::AddItemToSelection(PRUint32 aIndex)
+{
+  PRUint32 index = 0;
+  AccIterator iter(this, filters::GetSelectable, AccIterator::eTreeNav);
+  nsAccessible* selected = nsnull;
+  while ((selected = iter.GetNext()) && index < aIndex)
+    index++;
+
+  if (selected)
+    selected->SetSelected(PR_TRUE);
+
+  return static_cast<bool>(selected);
+}
+
+bool
+nsAccessible::RemoveItemFromSelection(PRUint32 aIndex)
+{
+  PRUint32 index = 0;
+  AccIterator iter(this, filters::GetSelectable, AccIterator::eTreeNav);
+  nsAccessible* selected = nsnull;
+  while ((selected = iter.GetNext()) && index < aIndex)
+    index++;
+
+  if (selected)
+    selected->SetSelected(PR_FALSE);
+
+  return static_cast<bool>(selected);
+}
+
+bool
+nsAccessible::SelectAll()
+{
+  bool success = false;
+  nsAccessible* selectable = nsnull;
+
+  AccIterator iter(this, filters::GetSelectable, AccIterator::eTreeNav);
+  while((selectable = iter.GetNext())) {
+    success = true;
+    selectable->SetSelected(PR_TRUE);
+  }
+  return success;
+}
+
+bool
+nsAccessible::UnselectAll()
+{
+  bool success = false;
+  nsAccessible* selected = nsnull;
+
+  AccIterator iter(this, filters::GetSelected, AccIterator::eTreeNav);
+  while ((selected = iter.GetNext())) {
+    success = true;
+    selected->SetSelected(PR_FALSE);
+  }
+  return success;
+}
+
+
 ////////////////////////////////////////////////////////////////////////////////
 // nsAccessible protected methods
 
 void
 nsAccessible::CacheChildren()
 {
   nsAccTreeWalker walker(mWeakShell, mContent, GetAllowsAnonChildAccessibles());
 
--- a/accessible/src/base/nsAccessible.h
+++ b/accessible/src/base/nsAccessible.h
@@ -365,16 +365,65 @@ public:
    */
   virtual nsAccessible* GetAnchor(PRUint32 aAnchorIndex);
 
   /**
    * Returns an anchor URI at the given index.
    */
   virtual already_AddRefed<nsIURI> GetAnchorURI(PRUint32 aAnchorIndex);
 
+  //////////////////////////////////////////////////////////////////////////////
+  // SelectAccessible
+
+  /**
+   * Return true if the accessible is a select control containing selectable
+   * items.
+   */
+  virtual bool IsSelect();
+
+  /**
+   * Return an array of selected items.
+   */
+  virtual already_AddRefed<nsIArray> SelectedItems();
+
+  /**
+   * Return the number of selected items.
+   */
+  virtual PRUint32 SelectedItemCount();
+
+  /**
+   * Return selected item at the given index.
+   */
+  virtual nsAccessible* GetSelectedItem(PRUint32 aIndex);
+
+  /**
+   * Determine if item at the given index is selected.
+   */
+  virtual bool IsItemSelected(PRUint32 aIndex);
+
+  /**
+   * Add item at the given index the selection. Return true if success.
+   */
+  virtual bool AddItemToSelection(PRUint32 aIndex);
+
+  /**
+   * Remove item at the given index from the selection. Return if success.
+   */
+  virtual bool RemoveItemFromSelection(PRUint32 aIndex);
+
+  /**
+   * Select all items. Return true if success.
+   */
+  virtual bool SelectAll();
+
+  /**
+   * Unselect all items. Return true if success.
+   */
+  virtual bool UnselectAll();
+
 protected:
 
   //////////////////////////////////////////////////////////////////////////////
   // Initializing, cache and tree traverse methods
 
   /**
    * Cache accessible children.
    */
--- a/accessible/src/base/nsDocAccessible.cpp
+++ b/accessible/src/base/nsDocAccessible.cpp
@@ -1169,17 +1169,17 @@ nsDocAccessible::ARIAAttributeChanged(ns
             eCaseMatters)))) {
     FireDelayedAccessibleEvent(nsIAccessibleEvent::EVENT_VALUE_CHANGE,
                                aContent);
     return;
   }
 
   if (aAttribute == nsAccessibilityAtoms::aria_multiselectable &&
       aContent->HasAttr(kNameSpaceID_None, nsAccessibilityAtoms::role)) {
-    // This affects whether the accessible supports nsIAccessibleSelectable.
+    // This affects whether the accessible supports SelectAccessible.
     // COM says we cannot change what interfaces are supported on-the-fly,
     // so invalidate this object. A new one will be created on demand.
     InvalidateCacheSubtree(aContent,
                            nsIAccessibilityService::NODE_SIGNIFICANT_CHANGE);
     return;
   }
 }
 
--- a/accessible/src/html/nsHTMLSelectAccessible.cpp
+++ b/accessible/src/html/nsHTMLSelectAccessible.cpp
@@ -52,273 +52,33 @@
 #include "nsIDOMHTMLInputElement.h"
 #include "nsIDOMHTMLOptGroupElement.h"
 #include "nsIDOMHTMLSelectElement.h"
 #include "nsIListControlFrame.h"
 #include "nsIServiceManager.h"
 #include "nsIMutableArray.h"
 
 ////////////////////////////////////////////////////////////////////////////////
-// nsHTMLSelectableAccessible
-////////////////////////////////////////////////////////////////////////////////
-
-////////////////////////////////////////////////////////////////////////////////
-// nsHTMLSelectableAccessible::iterator
-
-nsHTMLSelectableAccessible::iterator::iterator(nsHTMLSelectableAccessible *aParent, nsIWeakReference *aWeakShell): 
-  mWeakShell(aWeakShell), mParentSelect(aParent)
-{
-  mLength = mIndex = 0;
-  mSelCount = 0;
-
-  nsCOMPtr<nsIDOMHTMLSelectElement> htmlSelect =
-    do_QueryInterface(mParentSelect->mContent);
-  if (htmlSelect) {
-    htmlSelect->GetOptions(getter_AddRefs(mOptions));
-    if (mOptions)
-      mOptions->GetLength(&mLength);
-  }
-}
-
-PRBool nsHTMLSelectableAccessible::iterator::Advance() 
-{
-  if (mIndex < mLength) {
-    nsCOMPtr<nsIDOMNode> tempNode;
-    if (mOptions) {
-      mOptions->Item(mIndex, getter_AddRefs(tempNode));
-      mOption = do_QueryInterface(tempNode);
-    }
-    mIndex++;
-    return PR_TRUE;
-  }
-  return PR_FALSE;
-}
-
-void nsHTMLSelectableAccessible::iterator::CalcSelectionCount(PRInt32 *aSelectionCount)
-{
-  PRBool isSelected = PR_FALSE;
-
-  if (mOption)
-    mOption->GetSelected(&isSelected);
-
-  if (isSelected)
-    (*aSelectionCount)++;
-}
-
-void
-nsHTMLSelectableAccessible::iterator::AddAccessibleIfSelected(nsIMutableArray *aSelectedAccessibles, 
-                                                              nsPresContext *aContext)
-{
-  PRBool isSelected = PR_FALSE;
-  nsAccessible *optionAcc = nsnull;
-
-  if (mOption) {
-    mOption->GetSelected(&isSelected);
-    if (isSelected) {
-      nsCOMPtr<nsIContent> optionContent(do_QueryInterface(mOption));
-      optionAcc = GetAccService()->GetAccessibleInWeakShell(optionContent,
-                                                            mWeakShell);
-    }
-  }
-
-  if (optionAcc)
-    aSelectedAccessibles->AppendElement(static_cast<nsIAccessible*>(optionAcc),
-                                        PR_FALSE);
-}
-
-PRBool
-nsHTMLSelectableAccessible::iterator::GetAccessibleIfSelected(PRInt32 aIndex,
-                                                              nsPresContext *aContext, 
-                                                              nsIAccessible **aAccessible)
-{
-  PRBool isSelected = PR_FALSE;
-
-  *aAccessible = nsnull;
-
-  if (mOption) {
-    mOption->GetSelected(&isSelected);
-    if (isSelected) {
-      if (mSelCount == aIndex) {
-        nsCOMPtr<nsIContent> optionContent(do_QueryInterface(mOption));
-        nsAccessible *accessible =
-          GetAccService()->GetAccessibleInWeakShell(optionContent, mWeakShell);
-        NS_IF_ADDREF(*aAccessible = accessible);
-
-        return PR_TRUE;
-      }
-      mSelCount++;
-    }
-  }
-
-  return PR_FALSE;
-}
-
-void nsHTMLSelectableAccessible::iterator::Select(PRBool aSelect)
-{
-  if (mOption)
-    mOption->SetSelected(aSelect);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// nsHTMLSelectableAccessible
-
-nsHTMLSelectableAccessible::
-  nsHTMLSelectableAccessible(nsIContent *aContent, nsIWeakReference *aShell) :
-  nsAccessibleWrap(aContent, aShell)
-{
-}
-
-NS_IMPL_ISUPPORTS_INHERITED1(nsHTMLSelectableAccessible, nsAccessible, nsIAccessibleSelectable)
-
-// Helper methods
-NS_IMETHODIMP nsHTMLSelectableAccessible::ChangeSelection(PRInt32 aIndex, PRUint8 aMethod, PRBool *aSelState)
-{
-  *aSelState = PR_FALSE;
-
-  nsCOMPtr<nsIDOMHTMLSelectElement> htmlSelect(do_QueryInterface(mContent));
-  if (!htmlSelect)
-    return NS_ERROR_FAILURE;
-
-  nsCOMPtr<nsIDOMHTMLOptionsCollection> options;
-  htmlSelect->GetOptions(getter_AddRefs(options));
-  if (!options)
-    return NS_ERROR_FAILURE;
-
-  nsCOMPtr<nsIDOMNode> tempNode;
-  options->Item(aIndex, getter_AddRefs(tempNode));
-  nsCOMPtr<nsIDOMHTMLOptionElement> tempOption(do_QueryInterface(tempNode));
-  if (!tempOption)
-    return NS_ERROR_FAILURE;
-
-  tempOption->GetSelected(aSelState);
-  nsresult rv = NS_OK;
-  if (eSelection_Add == aMethod && !(*aSelState))
-    rv = tempOption->SetSelected(PR_TRUE);
-  else if (eSelection_Remove == aMethod && (*aSelState))
-    rv = tempOption->SetSelected(PR_FALSE);
-  return rv;
-}
-
-// Interface methods
-NS_IMETHODIMP nsHTMLSelectableAccessible::GetSelectedChildren(nsIArray **_retval)
-{
-  *_retval = nsnull;
-
-  nsCOMPtr<nsIMutableArray> selectedAccessibles =
-    do_CreateInstance(NS_ARRAY_CONTRACTID);
-  NS_ENSURE_STATE(selectedAccessibles);
-  
-  nsPresContext *context = GetPresContext();
-  if (!context)
-    return NS_ERROR_FAILURE;
-
-  nsHTMLSelectableAccessible::iterator iter(this, mWeakShell);
-  while (iter.Advance())
-    iter.AddAccessibleIfSelected(selectedAccessibles, context);
-
-  PRUint32 uLength = 0;
-  selectedAccessibles->GetLength(&uLength); 
-  if (uLength != 0) { // length of nsIArray containing selected options
-    *_retval = selectedAccessibles;
-    NS_ADDREF(*_retval);
-  }
-  return NS_OK;
-}
-
-// return the nth selected child's nsIAccessible object
-NS_IMETHODIMP nsHTMLSelectableAccessible::RefSelection(PRInt32 aIndex, nsIAccessible **_retval)
-{
-  *_retval = nsnull;
-
-  nsPresContext *context = GetPresContext();
-  if (!context)
-    return NS_ERROR_FAILURE;
-
-  nsHTMLSelectableAccessible::iterator iter(this, mWeakShell);
-  while (iter.Advance())
-    if (iter.GetAccessibleIfSelected(aIndex, context, _retval))
-      return NS_OK;
-  
-  // No matched item found
-  return NS_ERROR_FAILURE;
-}
-
-NS_IMETHODIMP nsHTMLSelectableAccessible::GetSelectionCount(PRInt32 *aSelectionCount)
-{
-  *aSelectionCount = 0;
-
-  nsHTMLSelectableAccessible::iterator iter(this, mWeakShell);
-  while (iter.Advance())
-    iter.CalcSelectionCount(aSelectionCount);
-  return NS_OK;
-}
-
-NS_IMETHODIMP nsHTMLSelectableAccessible::AddChildToSelection(PRInt32 aIndex)
-{
-  PRBool isSelected;
-  return ChangeSelection(aIndex, eSelection_Add, &isSelected);
-}
-
-NS_IMETHODIMP nsHTMLSelectableAccessible::RemoveChildFromSelection(PRInt32 aIndex)
-{
-  PRBool isSelected;
-  return ChangeSelection(aIndex, eSelection_Remove, &isSelected);
-}
-
-NS_IMETHODIMP nsHTMLSelectableAccessible::IsChildSelected(PRInt32 aIndex, PRBool *_retval)
-{
-  *_retval = PR_FALSE;
-  return ChangeSelection(aIndex, eSelection_GetState, _retval);
-}
-
-NS_IMETHODIMP nsHTMLSelectableAccessible::ClearSelection()
-{
-  nsHTMLSelectableAccessible::iterator iter(this, mWeakShell);
-  while (iter.Advance())
-    iter.Select(PR_FALSE);
-  return NS_OK;
-}
-
-NS_IMETHODIMP nsHTMLSelectableAccessible::SelectAllSelection(PRBool *_retval)
-{
-  *_retval = PR_FALSE;
-  
-  nsCOMPtr<nsIDOMHTMLSelectElement> htmlSelect(do_QueryInterface(mContent));
-  if (!htmlSelect)
-    return NS_ERROR_FAILURE;
-
-  htmlSelect->GetMultiple(_retval);
-  if (*_retval) {
-    nsHTMLSelectableAccessible::iterator iter(this, mWeakShell);
-    while (iter.Advance())
-      iter.Select(PR_TRUE);
-  }
-  return NS_OK;
-}
-
-
-////////////////////////////////////////////////////////////////////////////////
 // nsHTMLSelectListAccessible
 ////////////////////////////////////////////////////////////////////////////////
 
 nsHTMLSelectListAccessible::
   nsHTMLSelectListAccessible(nsIContent *aContent, nsIWeakReference *aShell) :
-  nsHTMLSelectableAccessible(aContent, aShell)
+  nsAccessibleWrap(aContent, aShell)
 {
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsHTMLSelectListAccessible: nsAccessible public
 
 nsresult
 nsHTMLSelectListAccessible::GetStateInternal(PRUint32 *aState,
                                              PRUint32 *aExtraState)
 {
-  nsresult rv = nsHTMLSelectableAccessible::GetStateInternal(aState,
-                                                             aExtraState);
+  nsresult rv = nsAccessibleWrap::GetStateInternal(aState, aExtraState);
   NS_ENSURE_A11Y_SUCCESS(rv, rv);
 
   // As a nsHTMLSelectListAccessible we can have the following states:
   //   nsIAccessibleStates::STATE_MULTISELECTABLE
   //   nsIAccessibleStates::STATE_EXTSELECTABLE
 
   nsCOMPtr<nsIDOMHTMLSelectElement> select(do_QueryInterface(mContent));
   if (select) {
@@ -348,16 +108,43 @@ nsHTMLSelectListAccessible::GetRoleInter
     *aRole = nsIAccessibleRole::ROLE_COMBOBOX_LIST;
   else
     *aRole = nsIAccessibleRole::ROLE_LISTBOX;
 
   return NS_OK;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
+// nsHTMLSelectListAccessible: SelectAccessible
+
+bool
+nsHTMLSelectListAccessible::IsSelect()
+{
+  return true;
+}
+
+bool
+nsHTMLSelectListAccessible::SelectAll()
+{
+  nsCOMPtr<nsIDOMHTMLSelectElement> selectElm(do_QueryInterface(mContent));
+  PRBool isMultiple = PR_FALSE;
+  selectElm->GetMultiple(&isMultiple);
+  return isMultiple ? nsAccessibleWrap::SelectAll() : false;
+}
+
+bool
+nsHTMLSelectListAccessible::UnselectAll()
+{
+  nsCOMPtr<nsIDOMHTMLSelectElement> selectElm(do_QueryInterface(mContent));
+  PRBool isMultiple = PR_FALSE;
+  selectElm->GetMultiple(&isMultiple);
+  return isMultiple ? nsAccessibleWrap::UnselectAll() : false;
+}
+
+////////////////////////////////////////////////////////////////////////////////
 // nsHTMLSelectListAccessible: nsAccessible protected
 
 void
 nsHTMLSelectListAccessible::CacheChildren()
 {
   // Cache accessibles for <optgroup> and <option> DOM decendents as children,
   // as well as the accessibles for them. Avoid whitespace text nodes. We want
   // to count all the <optgroup>s and <option>s as children because we want
@@ -671,16 +458,26 @@ NS_IMETHODIMP nsHTMLSelectOptionAccessib
       }
     }
     return NS_OK;
   }
 
   return NS_ERROR_INVALID_ARG;
 }
 
+NS_IMETHODIMP
+nsHTMLSelectOptionAccessible::SetSelected(PRBool aSelect)
+{
+  if (IsDefunct())
+    return NS_ERROR_FAILURE;
+
+  nsCOMPtr<nsIDOMHTMLOptionElement> optionElm(do_QueryInterface(mContent));
+  return optionElm->SetSelected(aSelect);
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // 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
   */
--- a/accessible/src/html/nsHTMLSelectAccessible.h
+++ b/accessible/src/html/nsHTMLSelectAccessible.h
@@ -34,17 +34,16 @@
  * 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 ***** */
 #ifndef __nsHTMLSelectAccessible_h__
 #define __nsHTMLSelectAccessible_h__
 
-#include "nsIAccessibleSelectable.h"
 #include "nsAccessibilityAtoms.h"
 #include "nsHTMLFormControlAccessible.h"
 #include "nsIDOMHTMLOptionsCollection.h"
 #include "nsIDOMHTMLOptionElement.h"
 #include "nsIDOMNode.h"
 
 class nsIMutableArray;
 
@@ -58,78 +57,35 @@ class nsIMutableArray;
   *        - nsHTMLSelectOptionAccessible
   *
   *  Comboboxes:
   *     - nsHTMLComboboxAccessible
   *        - nsHTMLComboboxListAccessible  [ inserted in accessible tree ]
   *           - nsHTMLSelectOptionAccessible(s)
   */
 
-/** ------------------------------------------------------ */
-/**  First, the common widgets                             */
-/** ------------------------------------------------------ */
-
-/*
- * The HTML implementation of nsIAccessibleSelectable.
- */
-class nsHTMLSelectableAccessible : public nsAccessibleWrap
-{
-public:
-
-  NS_DECL_ISUPPORTS_INHERITED
-  NS_DECL_NSIACCESSIBLESELECTABLE
-
-  nsHTMLSelectableAccessible(nsIContent *aContent, nsIWeakReference *aShell);
-  virtual ~nsHTMLSelectableAccessible() {}
-
-protected:
-
-  NS_IMETHOD ChangeSelection(PRInt32 aIndex, PRUint8 aMethod, PRBool *aSelState);
-
-  class iterator 
-  {
-  protected:
-    PRUint32 mLength;
-    PRUint32 mIndex;
-    PRInt32 mSelCount;
-    nsCOMPtr<nsIDOMHTMLOptionsCollection> mOptions;
-    nsCOMPtr<nsIDOMHTMLOptionElement> mOption;
-    nsCOMPtr<nsIWeakReference> mWeakShell;
-    nsHTMLSelectableAccessible *mParentSelect;
-
-  public:
-    iterator(nsHTMLSelectableAccessible *aParent, nsIWeakReference *aWeakShell);
-
-    void CalcSelectionCount(PRInt32 *aSelectionCount);
-    void Select(PRBool aSelect);
-    void AddAccessibleIfSelected(nsIMutableArray *aSelectedAccessibles, 
-                                 nsPresContext *aContext);
-    PRBool GetAccessibleIfSelected(PRInt32 aIndex, nsPresContext *aContext,
-                                   nsIAccessible **aAccessible);
-
-    PRBool Advance();
-  };
-
-  friend class iterator;
-};
-
 /*
  * The list that contains all the options in the select.
  */
-class nsHTMLSelectListAccessible : public nsHTMLSelectableAccessible
+class nsHTMLSelectListAccessible : public nsAccessibleWrap
 {
 public:
   
   nsHTMLSelectListAccessible(nsIContent *aContent, nsIWeakReference *aShell);
   virtual ~nsHTMLSelectListAccessible() {}
 
   // nsAccessible
   virtual nsresult GetRoleInternal(PRUint32 *aRole);
   virtual nsresult GetStateInternal(PRUint32 *aState, PRUint32 *aExtraState);
 
+  // SelectAccessible
+  virtual bool IsSelect();
+  virtual bool SelectAll();
+  virtual bool UnselectAll();
+
 protected:
 
   // nsAccessible
   virtual void CacheChildren();
 
   // nsHTMLSelectListAccessible
 
   /**
@@ -148,16 +104,17 @@ public:
   
   nsHTMLSelectOptionAccessible(nsIContent *aContent, nsIWeakReference *aShell);
   virtual ~nsHTMLSelectOptionAccessible() {}
 
   // nsIAccessible
   NS_IMETHOD DoAction(PRUint8 index);
   NS_IMETHOD GetActionName(PRUint8 aIndex, nsAString& aName);
   NS_IMETHOD GetNumActions(PRUint8 *_retval);
+  NS_IMETHOD SetSelected(PRBool aSelect);
 
   // nsAccessible
   virtual nsresult GetNameInternal(nsAString& aName);
   virtual nsresult GetRoleInternal(PRUint32 *aRole);
   virtual nsresult GetStateInternal(PRUint32 *aState, PRUint32 *aExtraState);
 
   virtual PRInt32 GetLevelInternal();
   virtual void GetPositionAndSizeInternal(PRInt32 *aPosInSet,
--- a/accessible/src/msaa/nsAccessibleWrap.cpp
+++ b/accessible/src/msaa/nsAccessibleWrap.cpp
@@ -39,17 +39,16 @@
 #include "nsAccessibleWrap.h"
 
 #include "nsAccessibilityAtoms.h"
 #include "nsAccUtils.h"
 #include "nsCoreUtils.h"
 #include "nsRelUtils.h"
 
 #include "nsIAccessibleDocument.h"
-#include "nsIAccessibleSelectable.h"
 #include "nsIAccessibleEvent.h"
 #include "nsIAccessibleWin32Object.h"
 
 #include "Accessible2_i.c"
 #include "AccessibleStates.h"
 
 #include "nsIMutableArray.h"
 #include "nsIDOMDocument.h"
@@ -692,17 +691,17 @@ AccessibleEnumerator::Skip(unsigned long
   mCurIndex += celt;
 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
   return S_OK;
 }
 
 /**
   * This method is called when a client wants to know which children of a node
   *  are selected. Note that this method can only find selected children for
-  *  nsIAccessible object which implement nsIAccessibleSelectable.
+  *  nsIAccessible object which implement SelectAccessible.
   *
   * The VARIANT return value arguement is expected to either contain a single IAccessible
   *  or an IEnumVARIANT of IAccessibles. We return the IEnumVARIANT regardless of the number
   *  of children selected, unless there are none selected in which case we return an empty
   *  VARIANT.
   *
   * We get the selected options from the select's accessible object and wrap
   *  those in an AccessibleEnumerator which we then put in the return VARIANT.
@@ -712,27 +711,22 @@ AccessibleEnumerator::Skip(unsigned long
   *  - the object is not the type that can have children selected
   */
 STDMETHODIMP nsAccessibleWrap::get_accSelection(VARIANT __RPC_FAR *pvarChildren)
 {
 __try {
   VariantInit(pvarChildren);
   pvarChildren->vt = VT_EMPTY;
 
-  nsCOMPtr<nsIAccessibleSelectable> 
-    select(do_QueryInterface(static_cast<nsIAccessible*>(this)));
-
-  if (select) {  // do we have an nsIAccessibleSelectable?
-    // we have an accessible that can have children selected
-    nsCOMPtr<nsIArray> selectedOptions;
-    // gets the selected options as nsIAccessibles.
-    select->GetSelectedChildren(getter_AddRefs(selectedOptions));
-    if (selectedOptions) { // false if the select has no children or none are selected
+  if (IsSelect()) {
+    nsCOMPtr<nsIArray> selectedItems = SelectedItems();
+    if (selectedItems) {
       // 1) Create and initialize the enumeration
-      nsRefPtr<AccessibleEnumerator> pEnum = new AccessibleEnumerator(selectedOptions);
+      nsRefPtr<AccessibleEnumerator> pEnum =
+        new AccessibleEnumerator(selectedItems);
 
       // 2) Put the enumerator in the VARIANT
       if (!pEnum)
         return E_OUTOFMEMORY;
       pvarChildren->vt = VT_UNKNOWN;    // this must be VT_UNKNOWN for an IEnumVARIANT
       NS_ADDREF(pvarChildren->punkVal = pEnum);
     }
   }
--- a/accessible/src/xforms/nsXFormsAccessible.cpp
+++ b/accessible/src/xforms/nsXFormsAccessible.cpp
@@ -311,290 +311,247 @@ nsXFormsEditableAccessible::GetStateInte
 
 NS_IMETHODIMP
 nsXFormsEditableAccessible::GetAssociatedEditor(nsIEditor **aEditor)
 {
   nsCOMPtr<nsIDOMNode> DOMNode(do_QueryInterface(mContent));
   return sXFormsService->GetEditor(DOMNode, aEditor);
 }
 
+////////////////////////////////////////////////////////////////////////////////
 // nsXFormsSelectableAccessible
-
-
-NS_IMPL_ISUPPORTS_INHERITED1(nsXFormsSelectableAccessible,
-                             nsXFormsEditableAccessible,
-                             nsIAccessibleSelectable)
+////////////////////////////////////////////////////////////////////////////////
 
 nsXFormsSelectableAccessible::
   nsXFormsSelectableAccessible(nsIContent *aContent, nsIWeakReference *aShell) :
   nsXFormsEditableAccessible(aContent, aShell), mIsSelect1Element(nsnull)
 {
   mIsSelect1Element =
     mContent->NodeInfo()->Equals(nsAccessibilityAtoms::select1);
 }
 
-NS_IMETHODIMP
-nsXFormsSelectableAccessible::GetSelectedChildren(nsIArray **aAccessibles)
+bool
+nsXFormsSelectableAccessible::IsSelect()
 {
-  NS_ENSURE_ARG_POINTER(aAccessibles);
+  return true;
+}
 
-  *aAccessibles = nsnull;
-
-  nsCOMPtr<nsIMutableArray> accessibles =
+already_AddRefed<nsIArray>
+nsXFormsSelectableAccessible::SelectedItems()
+{
+  nsCOMPtr<nsIMutableArray> selectedItems =
     do_CreateInstance(NS_ARRAY_CONTRACTID);
-  NS_ENSURE_TRUE(accessibles, NS_ERROR_OUT_OF_MEMORY);
+  if (!selectedItems)
+    return nsnull;
 
   nsresult rv;
   nsCOMPtr<nsIDOMNode> DOMNode(do_QueryInterface(mContent));
 
   if (mIsSelect1Element) {
-    nsCOMPtr<nsIDOMNode> item;
+    nsCOMPtr<nsIDOMNode> itemDOMNode;
     rv = sXFormsService->GetSelectedItemForSelect1(DOMNode,
-                                                   getter_AddRefs(item));
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    if (!item)
-      return NS_OK;
+                                                   getter_AddRefs(itemDOMNode));
+    if (NS_FAILED(rv) || !itemDOMNode)
+      return nsnull;
 
-    nsCOMPtr<nsIAccessible> accessible;
-    GetAccService()->GetAccessibleFor(item, getter_AddRefs(accessible));
-    NS_ENSURE_TRUE(accessible, NS_ERROR_FAILURE);
+    nsCOMPtr<nsINode> itemNode(do_QueryInterface(itemDOMNode));
+    nsIAccessible* item = GetAccService()->GetAccessibleInWeakShell(itemNode,
+                                                                    mWeakShell);
+    if (item)
+      selectedItems->AppendElement(item, PR_FALSE);
 
-    accessibles->AppendElement(accessible, PR_FALSE);
-    NS_ADDREF(*aAccessibles = accessibles);
-    return NS_OK;
+    nsIMutableArray* items = nsnull;
+    selectedItems.forget(&items);
+    return items;
   }
 
-  nsCOMPtr<nsIDOMNodeList> items;
+  nsCOMPtr<nsIDOMNodeList> itemNodeList;
   rv = sXFormsService->GetSelectedItemsForSelect(DOMNode,
-                                                 getter_AddRefs(items));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  if (!items)
-    return NS_OK;
+                                                 getter_AddRefs(itemNodeList));
+  if (NS_FAILED(rv) || !itemNodeList)
+    return nsnull;
 
   PRUint32 length = 0;
-  items->GetLength(&length);
-  if (!length)
-    return NS_OK;
-
+  itemNodeList->GetLength(&length);
   for (PRUint32 index = 0; index < length; index++) {
-    nsCOMPtr<nsIDOMNode> item;
-    items->Item(index, getter_AddRefs(item));
-    NS_ENSURE_TRUE(item, NS_ERROR_FAILURE);
+    nsCOMPtr<nsIDOMNode> itemDOMNode;
+    itemNodeList->Item(index, getter_AddRefs(itemDOMNode));
+    if (!itemDOMNode)
+      return nsnull;
 
-    nsCOMPtr<nsIAccessible> accessible;
-    GetAccService()->GetAccessibleFor(item, getter_AddRefs(accessible));
-    NS_ENSURE_TRUE(accessible, NS_ERROR_FAILURE);
-
-    accessibles->AppendElement(accessible, PR_FALSE);
+    nsCOMPtr<nsINode> itemNode(do_QueryInterface(itemDOMNode));
+    nsIAccessible* item = GetAccService()->GetAccessibleInWeakShell(itemNode,
+                                                                    mWeakShell);
+    if (item)
+      selectedItems->AppendElement(item, PR_FALSE);
   }
 
-  NS_ADDREF(*aAccessibles = accessibles);
-  return NS_OK;
+  nsIMutableArray* items = nsnull;
+  selectedItems.forget(&items);
+  return items;
 }
 
-NS_IMETHODIMP
-nsXFormsSelectableAccessible::GetSelectionCount(PRInt32 *aCount)
+PRUint32
+nsXFormsSelectableAccessible::SelectedItemCount()
 {
-  NS_ENSURE_ARG_POINTER(aCount);
-
-  *aCount = 0;
-
   nsresult rv;
   nsCOMPtr<nsIDOMNode> DOMNode(do_QueryInterface(mContent));
 
   if (mIsSelect1Element) {
     nsCOMPtr<nsIDOMNode> item;
     rv = sXFormsService->GetSelectedItemForSelect1(DOMNode,
                                                    getter_AddRefs(item));
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    if (item)
-      *aCount = 1;
-
-    return NS_OK;
+    return NS_SUCCEEDED(rv) && item ? 1 : 0;
   }
 
-  nsCOMPtr<nsIDOMNodeList> items;
+  nsCOMPtr<nsIDOMNodeList> itemNodeList;
   rv = sXFormsService->GetSelectedItemsForSelect(DOMNode,
-                                                 getter_AddRefs(items));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  if (!items)
-    return NS_OK;
+                                                 getter_AddRefs(itemNodeList));
+  if (NS_FAILED(rv) || !itemNodeList)
+    return 0;
 
   PRUint32 length = 0;
-  items->GetLength(&length);
-  if (length)
-    *aCount = length;
-
-  return NS_OK;
+  itemNodeList->GetLength(&length);
+  return length;
 }
 
-NS_IMETHODIMP
-nsXFormsSelectableAccessible::AddChildToSelection(PRInt32 aIndex)
+bool
+nsXFormsSelectableAccessible::AddItemToSelection(PRUint32 aIndex)
 {
-  nsCOMPtr<nsIDOMNode> item = GetItemByIndex(&aIndex);
-  if (!item)
-    return NS_OK;
+  nsCOMPtr<nsIDOMNode> itemDOMNode(do_QueryInterface(GetItemByIndex(&aIndex)));
+  if (!itemDOMNode)
+    return false;
 
   nsCOMPtr<nsIDOMNode> DOMNode(do_QueryInterface(mContent));
   if (mIsSelect1Element)
-    return sXFormsService->SetSelectedItemForSelect1(DOMNode, item);
+    sXFormsService->SetSelectedItemForSelect1(DOMNode, itemDOMNode);
+  else
+    sXFormsService->AddItemToSelectionForSelect(DOMNode, itemDOMNode);
 
-  return sXFormsService->AddItemToSelectionForSelect(DOMNode, item);
+  return true;
 }
 
-NS_IMETHODIMP
-nsXFormsSelectableAccessible::RemoveChildFromSelection(PRInt32 aIndex)
+bool
+nsXFormsSelectableAccessible::RemoveItemFromSelection(PRUint32 aIndex)
 {
-  nsCOMPtr<nsIDOMNode> item = GetItemByIndex(&aIndex);
-  if (!item)
-    return NS_OK;
+  nsCOMPtr<nsIDOMNode> itemDOMNode(do_QueryInterface(GetItemByIndex(&aIndex)));
+  if (!itemDOMNode)
+    return false;
 
   nsresult rv;
   nsCOMPtr<nsIDOMNode> DOMNode(do_QueryInterface(mContent));
   if (mIsSelect1Element) {
-    nsCOMPtr<nsIDOMNode> selitem;
-    rv = sXFormsService->GetSelectedItemForSelect1(DOMNode,
-                                                   getter_AddRefs(selitem));
-    NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
+    nsCOMPtr<nsIDOMNode> selItemDOMNode;
+    sXFormsService->GetSelectedItemForSelect1(DOMNode,
+                                              getter_AddRefs(selItemDOMNode));
+    if (selItemDOMNode == itemDOMNode)
+      sXFormsService->SetSelectedItemForSelect1(DOMNode, nsnull);
 
-    if (selitem != item)
-      return NS_ERROR_FAILURE;
-    return sXFormsService->SetSelectedItemForSelect1(DOMNode, nsnull);
+    return true;
   }
 
-  return sXFormsService->RemoveItemFromSelectionForSelect(DOMNode, item);
+  sXFormsService->RemoveItemFromSelectionForSelect(DOMNode, itemDOMNode);
+  return true;
 }
 
-NS_IMETHODIMP
-nsXFormsSelectableAccessible::RefSelection(PRInt32 aIndex,
-                                           nsIAccessible **aAccessible)
+nsAccessible*
+nsXFormsSelectableAccessible::GetSelectedItem(PRUint32 aIndex)
 {
-  NS_ENSURE_ARG_POINTER(aAccessible);
-  *aAccessible = nsnull;
-
   nsresult rv;
   nsCOMPtr<nsIDOMNode> DOMNode(do_QueryInterface(mContent));
   if (mIsSelect1Element) {
     if (aIndex != 0)
-      return NS_OK;
+      return nsnull;
 
-    nsCOMPtr<nsIDOMNode> item;
+    nsCOMPtr<nsIDOMNode> itemDOMNode;
     rv = sXFormsService->GetSelectedItemForSelect1(DOMNode,
-                                                   getter_AddRefs(item));
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    if (item)
-      return GetAccService()->GetAccessibleFor(item, aAccessible);
-    return NS_OK;
+                                                   getter_AddRefs(itemDOMNode));
+    if (NS_SUCCEEDED(rv) && itemDOMNode) {
+      nsCOMPtr<nsINode> itemNode(do_QueryInterface(itemDOMNode));
+      return GetAccService()->GetAccessibleInWeakShell(itemNode, mWeakShell);
+    }
+    return nsnull;
   }
 
-  nsCOMPtr<nsIDOMNodeList> items;
+  nsCOMPtr<nsIDOMNodeList> itemNodeList;
   rv = sXFormsService->GetSelectedItemsForSelect(DOMNode,
-                                                 getter_AddRefs(items));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  if (!items)
-    return NS_OK;
+                                                 getter_AddRefs(itemNodeList));
+  if (NS_FAILED(rv) || !itemNodeList)
+    return nsnull;
 
-  PRUint32 length = 0;
-  items->GetLength(&length);
-  if (aIndex < 0 || PRUint32(aIndex) >= length)
-    return NS_OK;
+  nsCOMPtr<nsIDOMNode> itemDOMNode;
+  itemNodeList->Item(aIndex, getter_AddRefs(itemDOMNode));
 
-  nsCOMPtr<nsIDOMNode> item;
-  items->Item(aIndex, getter_AddRefs(item));
-
-  nsCOMPtr<nsIAccessible> accessible;
-  return GetAccService()->GetAccessibleFor(item, getter_AddRefs(accessible));
+  nsCOMPtr<nsINode> itemNode(do_QueryInterface(itemDOMNode));
+  return GetAccService()->GetAccessibleInWeakShell(itemNode, mWeakShell);
 }
 
-NS_IMETHODIMP
-nsXFormsSelectableAccessible::IsChildSelected(PRInt32 aIndex,
-                                              PRBool *aIsSelected)
+bool
+nsXFormsSelectableAccessible::IsItemSelected(PRUint32 aIndex)
 {
-  NS_ENSURE_ARG_POINTER(aIsSelected);
-  *aIsSelected = PR_FALSE;
-
-  nsCOMPtr<nsIDOMNode> item = GetItemByIndex(&aIndex);
-  if (!item)
-    return NS_OK;
+  nsCOMPtr<nsIDOMNode> itemDOMNode(do_QueryInterface(GetItemByIndex(&aIndex)));
+  if (!itemDOMNode)
+    return false;
 
   nsresult rv;
   nsCOMPtr<nsIDOMNode> DOMNode(do_QueryInterface(mContent));
   if (mIsSelect1Element) {
-    nsCOMPtr<nsIDOMNode> selitem;
-    rv = sXFormsService->GetSelectedItemForSelect1(DOMNode,
-                                                   getter_AddRefs(selitem));
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    if (selitem == item)
-      *aIsSelected = PR_TRUE;
-    return NS_OK;
+    nsCOMPtr<nsIDOMNode> selItemDOMNode;
+    sXFormsService->GetSelectedItemForSelect1(DOMNode,
+                                              getter_AddRefs(selItemDOMNode));
+    return selItemDOMNode == itemDOMNode;
   }
 
-  return sXFormsService->IsSelectItemSelected(DOMNode, item, aIsSelected);
+  PRBool isSelected = PR_FALSE;
+  sXFormsService->IsSelectItemSelected(DOMNode, itemDOMNode, &isSelected);
+  return isSelected;
 }
 
-NS_IMETHODIMP
-nsXFormsSelectableAccessible::ClearSelection()
+bool
+nsXFormsSelectableAccessible::UnselectAll()
 {
   nsCOMPtr<nsIDOMNode> DOMNode(do_QueryInterface(mContent));
   if (mIsSelect1Element)
-    return sXFormsService->SetSelectedItemForSelect1(DOMNode, nsnull);
+    sXFormsService->SetSelectedItemForSelect1(DOMNode, nsnull);
 
-  return sXFormsService->ClearSelectionForSelect(DOMNode);
+  sXFormsService->ClearSelectionForSelect(DOMNode);
+  return true;
 }
 
-NS_IMETHODIMP
-nsXFormsSelectableAccessible::SelectAllSelection(PRBool *aMultipleSelection)
+bool
+nsXFormsSelectableAccessible::SelectAll()
 {
-  NS_ENSURE_ARG_POINTER(aMultipleSelection);
+  if (mIsSelect1Element)
+    return false;
 
-  if (mIsSelect1Element) {
-    *aMultipleSelection = PR_FALSE;
-    return NS_OK;
-  }
-
-  *aMultipleSelection = PR_TRUE;
   nsCOMPtr<nsIDOMNode> DOMNode(do_QueryInterface(mContent));
-  return sXFormsService->SelectAllItemsForSelect(DOMNode);
+  sXFormsService->SelectAllItemsForSelect(DOMNode);
+  return true;
 }
 
-already_AddRefed<nsIDOMNode>
-nsXFormsSelectableAccessible::GetItemByIndex(PRInt32 *aIndex,
-                                             nsIAccessible *aAccessible)
+nsIContent*
+nsXFormsSelectableAccessible::GetItemByIndex(PRUint32* aIndex,
+                                             nsAccessible* aAccessible)
 {
-  nsRefPtr<nsAccessible> accessible(do_QueryObject(aAccessible));
-  if (!accessible)
-    accessible = this;
-
+  nsAccessible* accessible = aAccessible ? aAccessible : this;
   PRInt32 childCount = accessible->GetChildCount();
   for (PRInt32 childIdx = 0; childIdx < childCount; childIdx++) {
     nsAccessible *child = accessible->GetChildAt(childIdx);
-
-    nsCOMPtr<nsIDOMNode> childNode(child->GetDOMNode());
-    nsCOMPtr<nsIContent> childContent(do_QueryInterface(childNode));
-    if (!childContent)
-      continue;
-
+    nsIContent* childContent = child->GetContent();
     nsINodeInfo *nodeInfo = childContent->NodeInfo();
     if (nodeInfo->NamespaceEquals(NS_LITERAL_STRING(NS_NAMESPACE_XFORMS))) {
       if (nodeInfo->Equals(nsAccessibilityAtoms::item)) {
         if (!*aIndex)
-          return childNode.forget();
+          return childContent;
 
         --*aIndex;
       } else if (nodeInfo->Equals(nsAccessibilityAtoms::choices)) {
-        nsIDOMNode *itemNode = GetItemByIndex(aIndex, child).get();
-        if (itemNode)
-          return itemNode;
+        nsIContent* itemContent = GetItemByIndex(aIndex, child);
+        if (itemContent)
+          return itemContent;
       }
     }
   }
 
   return nsnull;
 }
 
 
--- a/accessible/src/xforms/nsXFormsAccessible.h
+++ b/accessible/src/xforms/nsXFormsAccessible.h
@@ -157,22 +157,31 @@ public:
  * The class is base for accessible objects for XForms select and XForms
  * select1 elements.
  */
 class nsXFormsSelectableAccessible : public nsXFormsEditableAccessible
 {
 public:
   nsXFormsSelectableAccessible(nsIContent *aContent, nsIWeakReference *aShell);
 
-  NS_DECL_ISUPPORTS_INHERITED
-  NS_DECL_NSIACCESSIBLESELECTABLE
+  // SelectAccessible
+  virtual bool IsSelect();
+  virtual already_AddRefed<nsIArray> SelectedItems();
+  virtual PRUint32 SelectedItemCount();
+  virtual nsAccessible* GetSelectedItem(PRUint32 aIndex);
+  virtual bool IsItemSelected(PRUint32 aIndex);
+  virtual bool AddItemToSelection(PRUint32 aIndex);
+  virtual bool RemoveItemFromSelection(PRUint32 aIndex);
+  virtual bool SelectAll();
+  virtual bool UnselectAll();
 
 protected:
-  already_AddRefed<nsIDOMNode> GetItemByIndex(PRInt32 *aIndex,
-                                              nsIAccessible *aAccessible = nsnull);
+  nsIContent* GetItemByIndex(PRUint32* aIndex,
+                             nsAccessible* aAccessible = nsnull);
+
   PRBool mIsSelect1Element;
 };
 
 
 /**
  * The class is base for accessible objects for XForms item elements.
  */
 class nsXFormsSelectableItemAccessible : public nsXFormsAccessible
--- a/accessible/src/xul/nsXULListboxAccessible.cpp
+++ b/accessible/src/xul/nsXULListboxAccessible.cpp
@@ -874,17 +874,16 @@ nsXULListitemAccessible::
   nsXULMenuitemAccessible(aContent, aShell)
 {
   mIsCheckbox = mContent->AttrValueIs(kNameSpaceID_None,
                                       nsAccessibilityAtoms::type,
                                       nsAccessibilityAtoms::checkbox,
                                       eCaseMatters);
 }
 
-/** Inherit the ISupports impl from nsAccessible, we handle nsIAccessibleSelectable */
 NS_IMPL_ISUPPORTS_INHERITED0(nsXULListitemAccessible, nsAccessible)
 
 nsAccessible *
 nsXULListitemAccessible::GetListAccessible()
 {
   if (IsDefunct())
     return nsnull;
   
--- a/accessible/src/xul/nsXULMenuAccessible.cpp
+++ b/accessible/src/xul/nsXULMenuAccessible.cpp
@@ -60,209 +60,217 @@
 
 
 static NS_DEFINE_CID(kLookAndFeelCID, NS_LOOKANDFEEL_CID);
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsXULSelectableAccessible
 ////////////////////////////////////////////////////////////////////////////////
 
-// Helper methos
 nsXULSelectableAccessible::
   nsXULSelectableAccessible(nsIContent *aContent, nsIWeakReference *aShell) :
   nsAccessibleWrap(aContent, aShell)
 {
   mSelectControl = do_QueryInterface(aContent);
 }
 
-NS_IMPL_ISUPPORTS_INHERITED1(nsXULSelectableAccessible, nsAccessible, nsIAccessibleSelectable)
+////////////////////////////////////////////////////////////////////////////////
+// nsXULSelectableAccessible: nsAccessNode
 
 void
 nsXULSelectableAccessible::Shutdown()
 {
   mSelectControl = nsnull;
   nsAccessibleWrap::Shutdown();
 }
 
-nsresult nsXULSelectableAccessible::ChangeSelection(PRInt32 aIndex, PRUint8 aMethod, PRBool *aSelState)
-{
-  *aSelState = PR_FALSE;
-
-  if (!mSelectControl) {
-    return NS_ERROR_FAILURE;
-  }
-  nsAccessible* child = GetChildAt(aIndex);
-  NS_ENSURE_TRUE(child, NS_ERROR_FAILURE);
-
-  nsCOMPtr<nsIDOMNode> childNode;
-  child->GetDOMNode(getter_AddRefs(childNode));
-  nsCOMPtr<nsIDOMXULSelectControlItemElement> item(do_QueryInterface(childNode));
-  NS_ENSURE_TRUE(item, NS_ERROR_FAILURE);
+////////////////////////////////////////////////////////////////////////////////
+// nsXULSelectableAccessible: SelectAccessible
 
-  item->GetSelected(aSelState);
-  if (eSelection_GetState == aMethod) {
-    return NS_OK;
-  }
-
-  nsCOMPtr<nsIDOMXULMultiSelectControlElement> xulMultiSelect =
-    do_QueryInterface(mSelectControl);
-
-  if (eSelection_Add == aMethod && !(*aSelState)) {
-    return xulMultiSelect ? xulMultiSelect->AddItemToSelection(item) :
-                            mSelectControl->SetSelectedItem(item);
-  }
-  if (eSelection_Remove == aMethod && (*aSelState)) {
-    return xulMultiSelect ? xulMultiSelect->RemoveItemFromSelection(item) :
-                            mSelectControl->SetSelectedItem(nsnull);
-  }
-  return NS_ERROR_FAILURE;
+bool
+nsXULSelectableAccessible::IsSelect()
+{
+  return !!mSelectControl;
 }
 
 // Interface methods
-NS_IMETHODIMP nsXULSelectableAccessible::GetSelectedChildren(nsIArray **aChildren)
+already_AddRefed<nsIArray>
+nsXULSelectableAccessible::SelectedItems()
 {
-  *aChildren = nsnull;
-  if (!mSelectControl) {
-    return NS_ERROR_FAILURE;
-  }
-
-  nsCOMPtr<nsIMutableArray> selectedAccessibles =
+  nsCOMPtr<nsIMutableArray> selectedItems =
     do_CreateInstance(NS_ARRAY_CONTRACTID);
-  NS_ENSURE_STATE(selectedAccessibles);
+  if (!selectedItems)
+    return nsnull;
 
   // For XUL multi-select control
   nsCOMPtr<nsIDOMXULMultiSelectControlElement> xulMultiSelect =
     do_QueryInterface(mSelectControl);
   if (xulMultiSelect) {
     PRInt32 length = 0;
     xulMultiSelect->GetSelectedCount(&length);
     for (PRInt32 index = 0; index < length; index++) {
-      nsCOMPtr<nsIDOMXULSelectControlItemElement> selectedItem;
-      xulMultiSelect->GetSelectedItem(index, getter_AddRefs(selectedItem));
-      nsCOMPtr<nsIContent> selectedContent(do_QueryInterface(selectedItem));
-      nsAccessible *selectedAcc =
-        GetAccService()->GetAccessibleInWeakShell(selectedContent, mWeakShell);
-      if (selectedAcc)
-        selectedAccessibles->AppendElement(static_cast<nsIAccessible*>(selectedAcc),
-                                           PR_FALSE);
+      nsCOMPtr<nsIDOMXULSelectControlItemElement> itemElm;
+      xulMultiSelect->GetSelectedItem(index, getter_AddRefs(itemElm));
+      nsCOMPtr<nsINode> itemNode(do_QueryInterface(itemElm));
+      nsAccessible* item =
+        GetAccService()->GetAccessibleInWeakShell(itemNode, mWeakShell);
+      if (item)
+        selectedItems->AppendElement(static_cast<nsIAccessible*>(item),
+                                     PR_FALSE);
     }
   }
   else {  // Single select?
-    nsCOMPtr<nsIDOMXULSelectControlItemElement> selectedItem;
-    mSelectControl->GetSelectedItem(getter_AddRefs(selectedItem));
-    nsCOMPtr<nsIContent> selectedContent(do_QueryInterface(selectedItem));
-    if(selectedContent) {
-      nsAccessible *selectedAcc =
-        GetAccService()->GetAccessibleInWeakShell(selectedContent, mWeakShell);
-      if (selectedAcc)
-        selectedAccessibles->AppendElement(static_cast<nsIAccessible*>(selectedAcc),
-                                           PR_FALSE);
+    nsCOMPtr<nsIDOMXULSelectControlItemElement> itemElm;
+    mSelectControl->GetSelectedItem(getter_AddRefs(itemElm));
+    nsCOMPtr<nsINode> itemNode(do_QueryInterface(itemElm));
+    if(itemNode) {
+      nsAccessible* item =
+        GetAccService()->GetAccessibleInWeakShell(itemNode, mWeakShell);
+      if (item)
+        selectedItems->AppendElement(static_cast<nsIAccessible*>(item),
+                                     PR_FALSE);
     }
   }
 
-  PRUint32 uLength = 0;
-  selectedAccessibles->GetLength(&uLength);
-  if (uLength != 0) { // length of nsIArray containing selected options
-    NS_ADDREF(*aChildren = selectedAccessibles);
-  }
-
-  return NS_OK;
+  nsIMutableArray* items = nsnull;
+  selectedItems.forget(&items);
+  return items;
 }
 
-// return the nth selected child's nsIAccessible object
-NS_IMETHODIMP nsXULSelectableAccessible::RefSelection(PRInt32 aIndex, nsIAccessible **aAccessible)
+nsAccessible*
+nsXULSelectableAccessible::GetSelectedItem(PRUint32 aIndex)
 {
-  *aAccessible = nsnull;
-  if (!mSelectControl) {
-    return NS_ERROR_FAILURE;
-  }
-
-  nsCOMPtr<nsIDOMXULSelectControlItemElement> selectedItem;
-  nsCOMPtr<nsIDOMXULMultiSelectControlElement> xulMultiSelect =
+  nsCOMPtr<nsIDOMXULMultiSelectControlElement> multiSelectControl =
     do_QueryInterface(mSelectControl);
-  if (xulMultiSelect)
-    xulMultiSelect->GetSelectedItem(aIndex, getter_AddRefs(selectedItem));
 
-  if (aIndex == 0)
-    mSelectControl->GetSelectedItem(getter_AddRefs(selectedItem));
-
-  if (!selectedItem)
-    return NS_ERROR_FAILURE;
+  nsCOMPtr<nsIDOMXULSelectControlItemElement> itemElm;
+  if (multiSelectControl)
+    multiSelectControl->GetSelectedItem(aIndex, getter_AddRefs(itemElm));
+  else if (aIndex == 0)
+    mSelectControl->GetSelectedItem(getter_AddRefs(itemElm));
 
-  nsCOMPtr<nsIContent> selectedContent(do_QueryInterface(selectedItem));
-  nsAccessible *selectedAcc =
-    GetAccService()->GetAccessibleInWeakShell(selectedContent, mWeakShell);
-  if (!selectedAcc)
-    return NS_ERROR_FAILURE;
-
-  NS_ADDREF(*aAccessible = selectedAcc);
-  return NS_OK;
+  nsCOMPtr<nsINode> itemNode(do_QueryInterface(itemElm));
+  return itemNode ?
+    GetAccService()->GetAccessibleInWeakShell(itemNode, mWeakShell) : nsnull;
 }
 
-NS_IMETHODIMP nsXULSelectableAccessible::GetSelectionCount(PRInt32 *aSelectionCount)
+PRUint32
+nsXULSelectableAccessible::SelectedItemCount()
 {
-  *aSelectionCount = 0;
-  if (!mSelectControl) {
-    return NS_ERROR_FAILURE;
+  // For XUL multi-select control
+  nsCOMPtr<nsIDOMXULMultiSelectControlElement> multiSelectControl =
+    do_QueryInterface(mSelectControl);
+  if (multiSelectControl) {
+    PRInt32 count = 0;
+    multiSelectControl->GetSelectedCount(&count);
+    return count;
   }
 
-  // For XUL multi-select control
-  nsCOMPtr<nsIDOMXULMultiSelectControlElement> xulMultiSelect =
-    do_QueryInterface(mSelectControl);
-  if (xulMultiSelect)
-    return xulMultiSelect->GetSelectedCount(aSelectionCount);
-
   // For XUL single-select control/menulist
   PRInt32 index;
   mSelectControl->GetSelectedIndex(&index);
-  if (index >= 0)
-    *aSelectionCount = 1;
-  return NS_OK;
-}
-
-NS_IMETHODIMP nsXULSelectableAccessible::AddChildToSelection(PRInt32 aIndex)
-{
-  PRBool isSelected;
-  return ChangeSelection(aIndex, eSelection_Add, &isSelected);
+  return (index >= 0) ? 1 : 0;
 }
 
-NS_IMETHODIMP nsXULSelectableAccessible::RemoveChildFromSelection(PRInt32 aIndex)
+bool
+nsXULSelectableAccessible::AddItemToSelection(PRUint32 aIndex)
 {
-  PRBool isSelected;
-  return ChangeSelection(aIndex, eSelection_Remove, &isSelected);
-}
+  nsAccessible* item = GetChildAt(aIndex);
+  if (!item)
+    return false;
+
+  nsCOMPtr<nsIDOMXULSelectControlItemElement> itemElm =
+    do_QueryInterface(item->GetContent());
+  if (!itemElm)
+    return false;
 
-NS_IMETHODIMP nsXULSelectableAccessible::IsChildSelected(PRInt32 aIndex, PRBool *aIsSelected)
-{
-  *aIsSelected = PR_FALSE;
-  return ChangeSelection(aIndex, eSelection_GetState, aIsSelected);
+  PRBool isItemSelected = PR_FALSE;
+  itemElm->GetSelected(&isItemSelected);
+  if (isItemSelected)
+    return true;
+
+  nsCOMPtr<nsIDOMXULMultiSelectControlElement> multiSelectControl =
+    do_QueryInterface(mSelectControl);
+
+  if (multiSelectControl)
+    multiSelectControl->AddItemToSelection(itemElm);
+  else
+    mSelectControl->SetSelectedItem(itemElm);
+
+  return true;
 }
 
-NS_IMETHODIMP nsXULSelectableAccessible::ClearSelection()
+bool
+nsXULSelectableAccessible::RemoveItemFromSelection(PRUint32 aIndex)
 {
-  if (!mSelectControl) {
-    return NS_ERROR_FAILURE;
-  }
-  nsCOMPtr<nsIDOMXULMultiSelectControlElement> xulMultiSelect =
+  nsAccessible* item = GetChildAt(aIndex);
+  if (!item)
+    return false;
+
+  nsCOMPtr<nsIDOMXULSelectControlItemElement> itemElm =
+      do_QueryInterface(item->GetContent());
+  if (!itemElm)
+    return false;
+
+  PRBool isItemSelected = PR_FALSE;
+  itemElm->GetSelected(&isItemSelected);
+  if (!isItemSelected)
+    return true;
+
+  nsCOMPtr<nsIDOMXULMultiSelectControlElement> multiSelectControl =
     do_QueryInterface(mSelectControl);
-  return xulMultiSelect ? xulMultiSelect->ClearSelection() : mSelectControl->SetSelectedIndex(-1);
+
+  if (multiSelectControl)
+    multiSelectControl->RemoveItemFromSelection(itemElm);
+  else
+    mSelectControl->SetSelectedItem(nsnull);
+
+  return true;
 }
 
-NS_IMETHODIMP nsXULSelectableAccessible::SelectAllSelection(PRBool *aSucceeded)
+bool
+nsXULSelectableAccessible::IsItemSelected(PRUint32 aIndex)
 {
-  *aSucceeded = PR_TRUE;
+  nsAccessible* item = GetChildAt(aIndex);
+  if (!item)
+    return false;
+
+  nsCOMPtr<nsIDOMXULSelectControlItemElement> itemElm =
+    do_QueryInterface(item->GetContent());
+  if (!itemElm)
+    return false;
+
+  PRBool isItemSelected = PR_FALSE;
+  itemElm->GetSelected(&isItemSelected);
+  return isItemSelected;
+}
 
-  nsCOMPtr<nsIDOMXULMultiSelectControlElement> xulMultiSelect =
+bool
+nsXULSelectableAccessible::UnselectAll()
+{
+  nsCOMPtr<nsIDOMXULMultiSelectControlElement> multiSelectControl =
     do_QueryInterface(mSelectControl);
-  if (xulMultiSelect)
-    return xulMultiSelect->SelectAll();
+  multiSelectControl ?
+    multiSelectControl->ClearSelection() : mSelectControl->SetSelectedIndex(-1);
+
+  return true;
+}
+
+bool
+nsXULSelectableAccessible::SelectAll()
+{
+  nsCOMPtr<nsIDOMXULMultiSelectControlElement> multiSelectControl =
+    do_QueryInterface(mSelectControl);
+  if (multiSelectControl) {
+    multiSelectControl->SelectAll();
+    return true;
+  }
 
   // otherwise, don't support this method
-  *aSucceeded = PR_FALSE;
-  return NS_ERROR_NOT_IMPLEMENTED;
+  return false;
 }
 
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsXULMenuitemAccessible
 ////////////////////////////////////////////////////////////////////////////////
 
 nsXULMenuitemAccessible::
--- a/accessible/src/xul/nsXULMenuAccessible.h
+++ b/accessible/src/xul/nsXULMenuAccessible.h
@@ -35,37 +35,42 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef _nsXULMenuAccessible_H_
 #define _nsXULMenuAccessible_H_
 
 #include "nsAccessibleWrap.h"
-#include "nsIAccessibleSelectable.h"
 #include "nsIDOMXULSelectCntrlEl.h"
 
 /**
- * The basic implementation of nsIAccessibleSelectable.
+ * The basic implementation of SelectAccessible for XUL select controls.
  */
 class nsXULSelectableAccessible : public nsAccessibleWrap
 {
 public:
-  NS_DECL_ISUPPORTS_INHERITED
-  NS_DECL_NSIACCESSIBLESELECTABLE
-
   nsXULSelectableAccessible(nsIContent *aContent, nsIWeakReference *aShell);
   virtual ~nsXULSelectableAccessible() {}
 
   // nsAccessNode
   virtual void Shutdown();
 
+  // SelectAccessible
+  virtual bool IsSelect();
+  virtual already_AddRefed<nsIArray> SelectedItems();
+  virtual PRUint32 SelectedItemCount();
+  virtual nsAccessible* GetSelectedItem(PRUint32 aIndex);
+  virtual bool IsItemSelected(PRUint32 aIndex);
+  virtual bool AddItemToSelection(PRUint32 aIndex);
+  virtual bool RemoveItemFromSelection(PRUint32 aIndex);
+  virtual bool SelectAll();
+  virtual bool UnselectAll();
+
 protected:
-  nsresult ChangeSelection(PRInt32 aIndex, PRUint8 aMethod, PRBool *aSelState);
-
   // nsIDOMXULMultiSelectControlElement inherits from this, so we'll always have
   // one of these if the widget is valid and not defunct
   nsCOMPtr<nsIDOMXULSelectControlElement> mSelectControl;
 };
 
 /**
  * Used for XUL menu, menuitem elements.
  */
--- a/accessible/src/xul/nsXULTreeAccessible.cpp
+++ b/accessible/src/xul/nsXULTreeAccessible.cpp
@@ -52,17 +52,17 @@
 #include "nsComponentManagerUtils.h"
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsXULTreeAccessible
 ////////////////////////////////////////////////////////////////////////////////
 
 nsXULTreeAccessible::
   nsXULTreeAccessible(nsIContent *aContent, nsIWeakReference *aShell) :
-  nsXULSelectableAccessible(aContent, aShell)
+  nsAccessibleWrap(aContent, aShell)
 {
   mTree = nsCoreUtils::GetTreeBoxObject(aContent);
   if (mTree)
     mTree->GetView(getter_AddRefs(mTreeView));
 
   NS_ASSERTION(mTree && mTreeView, "Can't get mTree or mTreeView!\n");
 
   mAccessibleCache.Init(kDefaultTreeCacheSize);
@@ -80,20 +80,20 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsXULTreeAccessible,
                                                 nsAccessible)
 ClearCache(tmp->mAccessibleCache);
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsXULTreeAccessible)
 NS_INTERFACE_MAP_STATIC_AMBIGUOUS(nsXULTreeAccessible)
-NS_INTERFACE_MAP_END_INHERITING(nsXULSelectableAccessible)
+NS_INTERFACE_MAP_END_INHERITING(nsAccessible)
 
-NS_IMPL_ADDREF_INHERITED(nsXULTreeAccessible, nsXULSelectableAccessible)
-NS_IMPL_RELEASE_INHERITED(nsXULTreeAccessible, nsXULSelectableAccessible)
+NS_IMPL_ADDREF_INHERITED(nsXULTreeAccessible, nsAccessible)
+NS_IMPL_RELEASE_INHERITED(nsXULTreeAccessible, nsAccessible)
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsXULTreeAccessible: nsAccessible implementation
 
 nsresult
 nsXULTreeAccessible::GetStateInternal(PRUint32 *aState, PRUint32 *aExtraState)
 {
   // Get focus status from base class.
@@ -155,32 +155,32 @@ nsXULTreeAccessible::GetValue(nsAString&
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsXULTreeAccessible: nsAccessNode implementation
 
 PRBool
 nsXULTreeAccessible::IsDefunct()
 {
-  return nsXULSelectableAccessible::IsDefunct() || !mTree || !mTreeView;
+  return nsAccessibleWrap::IsDefunct() || !mTree || !mTreeView;
 }
 
 void
 nsXULTreeAccessible::Shutdown()
 {
   // XXX: we don't remove accessible from document cache if shutdown wasn't
   // initiated by document destroying. Note, we can't remove accessible from
   // document cache here while document is going to be shutdown. Note, this is
   // not unique place where we have similar problem.
   ClearCache(mAccessibleCache);
 
   mTree = nsnull;
   mTreeView = nsnull;
 
-  nsXULSelectableAccessible::Shutdown();
+  nsAccessibleWrap::Shutdown();
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsXULTreeAccessible: nsAccessible implementation (put methods here)
 
 nsresult
 nsXULTreeAccessible::GetRoleInternal(PRUint32 *aRole)
 {
@@ -257,191 +257,183 @@ nsXULTreeAccessible::GetChildAtPoint(PRI
   nsCOMPtr<nsITreeColumn> column;
   nsCAutoString childEltUnused;
   mTree->GetCellAt(clientX, clientY, &row, getter_AddRefs(column),
                    childEltUnused);
 
   // If we failed to find tree cell for the given point then it might be
   // tree columns.
   if (row == -1 || !column)
-    return nsXULSelectableAccessible::
-      GetChildAtPoint(aX, aY, aDeepestChild, aChild);
+    return nsAccessibleWrap::GetChildAtPoint(aX, aY, aDeepestChild, aChild);
 
   nsAccessible *child = GetTreeItemAccessible(row);
   if (aDeepestChild && child) {
     // Look for accessible cell for the found item accessible.
     nsRefPtr<nsXULTreeItemAccessibleBase> treeitem = do_QueryObject(child);
 
     nsAccessible *cell = treeitem->GetCellAccessible(column);
     if (cell)
       child = cell;
   }
 
   NS_IF_ADDREF(*aChild = child);
   return NS_OK;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
-// nsXULTreeAccessible: nsAccessibleSelectable implementation
+// nsXULTreeAccessible: SelectAccessible
 
-NS_IMETHODIMP nsXULTreeAccessible::GetSelectedChildren(nsIArray **_retval)
+bool
+nsXULTreeAccessible::IsSelect()
 {
-  // Ask tree selection to get all selected children
-  *_retval = nsnull;
+  return true;
+}
 
-  if (IsDefunct())
-    return NS_ERROR_FAILURE;
-
+already_AddRefed<nsIArray>
+nsXULTreeAccessible::SelectedItems()
+{
   nsCOMPtr<nsITreeSelection> selection;
   mTreeView->GetSelection(getter_AddRefs(selection));
   if (!selection)
-    return NS_ERROR_FAILURE;
-  nsCOMPtr<nsIMutableArray> selectedAccessibles =
+    return nsnull;
+
+  nsCOMPtr<nsIMutableArray> selectedItems =
     do_CreateInstance(NS_ARRAY_CONTRACTID);
-  NS_ENSURE_STATE(selectedAccessibles);
+  if (!selectedItems)
+    return nsnull;
 
   PRInt32 rowIndex, rowCount;
   PRBool isSelected;
   mTreeView->GetRowCount(&rowCount);
   for (rowIndex = 0; rowIndex < rowCount; rowIndex++) {
     selection->IsSelected(rowIndex, &isSelected);
     if (isSelected) {
-      nsIAccessible *tempAccessible = GetTreeItemAccessible(rowIndex);
-      NS_ENSURE_STATE(tempAccessible);
-
-      selectedAccessibles->AppendElement(tempAccessible, PR_FALSE);
+      nsIAccessible* item = GetTreeItemAccessible(rowIndex);
+      if (item)
+        selectedItems->AppendElement(item, PR_FALSE);
     }
   }
 
-  PRUint32 length;
-  selectedAccessibles->GetLength(&length);
-  if (length != 0) {
-    *_retval = selectedAccessibles;
-    NS_IF_ADDREF(*_retval);
-  }
-
-  return NS_OK;
+  nsIMutableArray* items = nsnull;
+  selectedItems.forget(&items);
+  return items;
 }
 
-NS_IMETHODIMP nsXULTreeAccessible::GetSelectionCount(PRInt32 *aSelectionCount)
+PRUint32
+nsXULTreeAccessible::SelectedItemCount()
 {
-  *aSelectionCount = 0;
-
-  if (IsDefunct())
-    return NS_ERROR_FAILURE;
-
   nsCOMPtr<nsITreeSelection> selection;
   mTreeView->GetSelection(getter_AddRefs(selection));
-  if (selection)
-    selection->GetCount(aSelectionCount);
+  if (selection) {
+    PRInt32 count = 0;
+    selection->GetCount(&count);
+    return count;
+  }
 
-  return NS_OK;
+  return 0;
 }
 
-NS_IMETHODIMP nsXULTreeAccessible::ChangeSelection(PRInt32 aIndex, PRUint8 aMethod, PRBool *aSelState)
+bool
+nsXULTreeAccessible::AddItemToSelection(PRUint32 aIndex)
 {
-  if (IsDefunct())
-    return NS_ERROR_FAILURE;
-
   nsCOMPtr<nsITreeSelection> selection;
   mTreeView->GetSelection(getter_AddRefs(selection));
   if (selection) {
-    selection->IsSelected(aIndex, aSelState);
-    if ((!(*aSelState) && eSelection_Add == aMethod) || 
-        ((*aSelState) && eSelection_Remove == aMethod))
-      return selection->ToggleSelect(aIndex);
-  }
-
-  return NS_OK;
-}
+    PRBool isSelected = PR_FALSE;
+    selection->IsSelected(aIndex, &isSelected);
+    if (!isSelected)
+      selection->ToggleSelect(aIndex);
 
-NS_IMETHODIMP nsXULTreeAccessible::AddChildToSelection(PRInt32 aIndex)
-{
-  PRBool isSelected;
-  return ChangeSelection(aIndex, eSelection_Add, &isSelected);
-}
-
-NS_IMETHODIMP nsXULTreeAccessible::RemoveChildFromSelection(PRInt32 aIndex)
-{
-  PRBool isSelected;
-  return ChangeSelection(aIndex, eSelection_Remove, &isSelected);
+    return true;
+  }
+  return false;
 }
 
-NS_IMETHODIMP nsXULTreeAccessible::IsChildSelected(PRInt32 aIndex, PRBool *_retval)
+bool
+nsXULTreeAccessible::RemoveItemFromSelection(PRUint32 aIndex)
 {
-  return ChangeSelection(aIndex, eSelection_GetState, _retval);
-}
-
-NS_IMETHODIMP nsXULTreeAccessible::ClearSelection()
-{
-  if (IsDefunct())
-    return NS_ERROR_FAILURE;
-
   nsCOMPtr<nsITreeSelection> selection;
   mTreeView->GetSelection(getter_AddRefs(selection));
-  if (selection)
-    selection->ClearSelection();
+  if (selection) {
+    PRBool isSelected = PR_FALSE;
+    selection->IsSelected(aIndex, &isSelected);
+    if (isSelected)
+      selection->ToggleSelect(aIndex);
 
-  return NS_OK;
+    return true;
+  }
+  return false;
 }
 
-NS_IMETHODIMP
-nsXULTreeAccessible::RefSelection(PRInt32 aIndex, nsIAccessible **aAccessible)
+bool
+nsXULTreeAccessible::IsItemSelected(PRUint32 aIndex)
 {
-  NS_ENSURE_ARG_POINTER(aAccessible);
-  *aAccessible = nsnull;
+  nsCOMPtr<nsITreeSelection> selection;
+  mTreeView->GetSelection(getter_AddRefs(selection));
+  if (selection) {
+    PRBool isSelected = PR_FALSE;
+    selection->IsSelected(aIndex, &isSelected);
+    return isSelected;
+  }
+  return false;
+}
 
-  if (IsDefunct())
-    return NS_ERROR_FAILURE;
-
+bool
+nsXULTreeAccessible::UnselectAll()
+{
   nsCOMPtr<nsITreeSelection> selection;
   mTreeView->GetSelection(getter_AddRefs(selection));
   if (!selection)
-    return NS_ERROR_FAILURE;
+    return false;
+
+  selection->ClearSelection();
+  return true;
+}
+
+nsAccessible*
+nsXULTreeAccessible::GetSelectedItem(PRUint32 aIndex)
+{
+  nsCOMPtr<nsITreeSelection> selection;
+  mTreeView->GetSelection(getter_AddRefs(selection));
+  if (!selection)
+    return nsnull;
 
   PRInt32 rowIndex, rowCount;
   PRInt32 selCount = 0;
   PRBool isSelected;
   mTreeView->GetRowCount(&rowCount);
   for (rowIndex = 0; rowIndex < rowCount; rowIndex++) {
     selection->IsSelected(rowIndex, &isSelected);
     if (isSelected) {
-      if (selCount == aIndex) {
-        NS_IF_ADDREF(*aAccessible = GetTreeItemAccessible(rowIndex));
-        return NS_OK;
-      }
+      if (selCount == aIndex)
+        return GetTreeItemAccessible(rowIndex);
+
       selCount++;
     }
   }
 
-  return NS_OK;
+  return nsnull;
 }
 
-NS_IMETHODIMP
-nsXULTreeAccessible::SelectAllSelection(PRBool *aIsMultiSelectable)
+bool
+nsXULTreeAccessible::SelectAll()
 {
-  NS_ENSURE_ARG_POINTER(aIsMultiSelectable);
-  *aIsMultiSelectable = PR_FALSE;
-
-  if (IsDefunct())
-    return NS_ERROR_FAILURE;
-
   // see if we are multiple select if so set ourselves as such
   nsCOMPtr<nsITreeSelection> selection;
   mTreeView->GetSelection(getter_AddRefs(selection));
   if (selection) {
     PRBool single = PR_FALSE;
     selection->GetSingle(&single);
     if (!single) {
-      *aIsMultiSelectable = PR_TRUE;
       selection->SelectAll();
+      return true;
     }
   }
 
-  return NS_OK;
+  return false;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsXULTreeAccessible: nsAccessible implementation
 
 nsAccessible*
 nsXULTreeAccessible::GetChildAt(PRUint32 aIndex)
 {
--- a/accessible/src/xul/nsXULTreeAccessible.h
+++ b/accessible/src/xul/nsXULTreeAccessible.h
@@ -56,17 +56,17 @@ const PRUint32 kDefaultTreeCacheSize = 2
 #define NS_XULTREEACCESSIBLE_IMPL_CID                   \
 {  /* 2692e149-6176-42ee-b8e1-2c44b04185e3 */           \
   0x2692e149,                                           \
   0x6176,                                               \
   0x42ee,                                               \
   { 0xb8, 0xe1, 0x2c, 0x44, 0xb0, 0x41, 0x85, 0xe3 }    \
 }
 
-class nsXULTreeAccessible : public nsXULSelectableAccessible
+class nsXULTreeAccessible : public nsAccessibleWrap
 {
 public:
   using nsAccessible::GetChildCount;
   using nsAccessible::GetChildAt;
   using nsAccessible::GetChildAtPoint;
 
   nsXULTreeAccessible(nsIContent *aContent, nsIWeakReference *aShell);
 
@@ -74,33 +74,41 @@ public:
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsXULTreeAccessible,
                                            nsAccessible)
 
   // nsIAccessible
   NS_IMETHOD GetValue(nsAString& aValue);
   NS_IMETHOD GetFocusedChild(nsIAccessible **aFocusedChild);
 
-  // nsIAccessibleSelectable
-  NS_DECL_NSIACCESSIBLESELECTABLE
-
   // nsAccessNode
   virtual PRBool IsDefunct();
   virtual void Shutdown();
 
   // nsAccessible
   virtual nsresult GetRoleInternal(PRUint32 *aRole);
   virtual nsresult GetStateInternal(PRUint32 *aState, PRUint32 *aExtraState);
   virtual nsresult GetChildAtPoint(PRInt32 aX, PRInt32 aY,
                                    PRBool aDeepestChild,
                                    nsIAccessible **aChild);
 
   virtual nsAccessible* GetChildAt(PRUint32 aIndex);
   virtual PRInt32 GetChildCount();
 
+  // SelectAccessible
+  virtual bool IsSelect();
+  virtual already_AddRefed<nsIArray> SelectedItems();
+  virtual PRUint32 SelectedItemCount();
+  virtual nsAccessible* GetSelectedItem(PRUint32 aIndex);
+  virtual bool IsItemSelected(PRUint32 aIndex);
+  virtual bool AddItemToSelection(PRUint32 aIndex);
+  virtual bool RemoveItemFromSelection(PRUint32 aIndex);
+  virtual bool SelectAll();
+  virtual bool UnselectAll();
+
   // nsXULTreeAccessible
 
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_XULTREEACCESSIBLE_IMPL_CID)
 
   /**
    * Return tree item accessible at the givem row. If accessible doesn't exist
    * in the cache then create and cache it.
    *
@@ -139,18 +147,16 @@ protected:
   /**
    * Creates tree item accessible for the given row index.
    */
   virtual already_AddRefed<nsAccessible> CreateTreeItemAccessible(PRInt32 aRow);
 
   nsCOMPtr<nsITreeBoxObject> mTree;
   nsCOMPtr<nsITreeView> mTreeView;
   nsAccessibleHashtable mAccessibleCache;
-
-  NS_IMETHOD ChangeSelection(PRInt32 aIndex, PRUint8 aMethod, PRBool *aSelState);
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsXULTreeAccessible,
                               NS_XULTREEACCESSIBLE_IMPL_CID)
 
 /**
  * Base class for tree item accessibles.
  */
--- a/accessible/tests/mochitest/selectable.js
+++ b/accessible/tests/mochitest/selectable.js
@@ -1,36 +1,82 @@
 /**
  * Test selection getter methods of nsIAccessibleSelectable.
  *
  * @param aIdentifier        [in] selectable container accessible
  * @param aSelectedChildren  [in] array of selected children
  */
-function testSelectableSelection(aIdentifier, aSelectedChildren)
+function testSelectableSelection(aIdentifier, aSelectedChildren, aMsg)
 {
   var acc = getAccessible(aIdentifier, [nsIAccessibleSelectable]);
   if (!acc)
     return;
 
+  var msg = aMsg ? aMsg : "";
   var len = aSelectedChildren.length;
 
   // getSelectedChildren
   var selectedChildren = acc.GetSelectedChildren();
-  is(selectedChildren ? selectedChildren.length : 0, aSelectedChildren.length,
-     "getSelectedChildren: wrong selected children count for " + prettyName(aIdentifier));
+  is(selectedChildren ? selectedChildren.length : 0, len,
+     msg + "getSelectedChildren: wrong selected children count for " +
+     prettyName(aIdentifier));
 
   for (var idx = 0; idx < len; idx++) {
     var expectedAcc = getAccessible(aSelectedChildren[idx]);
-    is(selectedChildren.queryElementAt(idx, nsIAccessible), expectedAcc,
-       "getSelectedChildren: wrong selected child at index " + idx + " for " + prettyName(aIdentifier));
+    var actualAcc = selectedChildren.queryElementAt(idx, nsIAccessible);
+    is(actualAcc, expectedAcc,
+       msg + "getSelectedChildren: wrong selected child at index " + idx +
+       " for " + prettyName(aIdentifier) + " { actual : " +
+       prettyName(actualAcc) + ", expected: " + prettyName(expectedAcc) + "}");
   }
 
   // selectionCount
-  is(acc.selectionCount, aSelectedChildren.length,
-     "selectionCount: wrong selected children count for " + prettyName(aIdentifier));
+  // XXX: nsIAccessibleText and nsIAccessibleSelectable both have
+  // selectionCount property.
+  //is(acc.selectionCount, aSelectedChildren.length,
+  //   "selectionCount: wrong selected children count for " + prettyName(aIdentifier));
 
   // refSelection
   for (var idx = 0; idx < len; idx++) {
     var expectedAcc = getAccessible(aSelectedChildren[idx]);
     is(acc.refSelection(idx), expectedAcc,
-       "refSelection: wrong selected child at index " + idx + " for " + prettyName(aIdentifier));
+       msg + "refSelection: wrong selected child at index " + idx + " for " +
+       prettyName(aIdentifier));
+  }
+
+  // isChildSelected
+  testIsChildSelected(acc, acc, { value: 0 }, aSelectedChildren, msg);
+}
+
+/**
+ * Test isChildSelected method, helper for testSelectableSelection
+ */
+function testIsChildSelected(aSelectAcc, aTraversedAcc, aIndexObj, aSelectedChildren, aMsg)
+{
+  var childCount = aTraversedAcc.childCount;
+  for (var idx = 0; idx < childCount; idx++) {
+    var child = aTraversedAcc.getChildAt(idx);
+    var [state, extraState] = getStates(child);
+    if (state & STATE_SELECTABLE) {
+      var isSelected = false;
+      var len = aSelectedChildren.length;
+      for (var jdx = 0; jdx < len; jdx++) {
+        if (child == getAccessible(aSelectedChildren[jdx])) {
+          isSelected = true;
+          break;
+        }
+      }
+
+      // isChildSelected
+      is(aSelectAcc.isChildSelected(aIndexObj.value++), isSelected,
+         aMsg + "isChildSelected: wrong selected child " + prettyName(child) +
+         " for " + prettyName(aSelectAcc));
+
+      // selected state
+      testStates(child, isSelected ? STATE_SELECTED : 0, 0,
+                 !isSelected ? STATE_SELECTED : 0 , 0);
+
+      continue;
+    }
+
+    testIsChildSelected(aSelectAcc, child, aIndexObj, aSelectedChildren);
   }
 }
--- a/accessible/tests/mochitest/selectable/Makefile.in
+++ b/accessible/tests/mochitest/selectable/Makefile.in
@@ -42,14 +42,17 @@ srcdir		= @srcdir@
 VPATH		= @srcdir@
 relativesrcdir  = accessible/selectable
 
 include $(DEPTH)/config/autoconf.mk
 include $(topsrcdir)/config/rules.mk
 
 _TEST_FILES =\
 		test_aria.html \
+		test_listbox.xul \
+		test_menu.xul \
+		test_menulist.xul \
 		test_select.html \
 		test_tree.xul \
 		$(NULL)
 
 libs:: $(_TEST_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/a11y/$(relativesrcdir)
--- a/accessible/tests/mochitest/selectable/test_aria.html
+++ b/accessible/tests/mochitest/selectable/test_aria.html
@@ -13,16 +13,18 @@
   <script type="application/javascript"
           src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
 
   <script type="application/javascript"
           src="../common.js"></script>
   <script type="application/javascript"
           src="../role.js"></script>
   <script type="application/javascript"
+          src="../states.js"></script>
+  <script type="application/javascript"
           src="../selectable.js"></script>
 
   <script type="application/javascript">
     function testSelectable(aID, aSelectableChildren)
     {
       var acc = getAccessible(aID, [nsIAccessibleSelectable]);
 
       testSelectableSelection(acc, []);
@@ -31,42 +33,98 @@
       testSelectableSelection(acc, aSelectableChildren);
 
       acc.clearSelection();
       testSelectableSelection(acc, []);
     }
 
     function doTest()
     {
+      //////////////////////////////////////////////////////////////////////////
+      // role="list"
+
       var id = "list1";
       ok(isAccessible(id, [nsIAccessibleSelectable]),
          "No selectable accessible for " + id);
 
+      testSelectableSelection(id, [ ]);
+
+      var select = getAccessible(id, [nsIAccessibleSelectable]);
+      select.addChildToSelection(0);
+      testSelectableSelection(id, [ ]);
+      select.removeChildFromSelection(0);
+      testSelectableSelection(id, [ ]);
+      select.selectAllSelection();
+      testSelectableSelection(id, [ ]);
+      select.clearSelection();
+      testSelectableSelection(id, [ ]);
+
+      //////////////////////////////////////////////////////////////////////////
+      // role="listbox"
+
       id = "listbox1";
       ok(isAccessible(id, [nsIAccessibleSelectable]),
          "No selectable accessible for " + id);
 
+      testSelectableSelection(id, [ ]);
+
+      //////////////////////////////////////////////////////////////////////////
+      // role="listbox" aria-multiselectable
+
       id = "listbox2";
       ok(isAccessible(id, [nsIAccessibleSelectable]),
          "No selectable accessible for " + id);
 
+      testSelectableSelection(id, [ ]);
+
+      select = getAccessible(id, [nsIAccessibleSelectable]);
+      select.addChildToSelection(0);
+      testSelectableSelection(id, [ "listbox2_item1" ]);
+      select.removeChildFromSelection(0);
+      testSelectableSelection(id, [ ]);
+      select.selectAllSelection();
+      testSelectableSelection(id, [ "listbox2_item1", "listbox2_item2" ]);
+      select.clearSelection();
+      testSelectableSelection(id, [ ]);
+
+      //////////////////////////////////////////////////////////////////////////
+      // role="grid"
+
       id = "grid1";
       ok(isAccessible(id, [nsIAccessibleSelectable]),
          "No selectable accessible for " + id);
 
+      testSelectableSelection(id, [ ]);
+
+      //////////////////////////////////////////////////////////////////////////
+      // role="tree"
+
       id = "tree1";
       ok(isAccessible(id, [nsIAccessibleSelectable]),
          "No selectable accessible for " + id);
 
+      testSelectableSelection(id, [ ]);
+
+      //////////////////////////////////////////////////////////////////////////
+      // role="treegrid"
+
       id = "treegrid1";
       ok(isAccessible(id, [nsIAccessibleSelectable]),
          "No selectable accessible for " + id);
 
-      // Test selection methods for selectable children in subtree.
-      testSelectable("grid2",
+      testSelectableSelection(id, [ ]);
+
+      //////////////////////////////////////////////////////////////////////////
+      // role="grid" aria-multiselectable, selectable children in subtree
+
+      id = "grid2";
+      ok(isAccessible(id, [nsIAccessibleSelectable]),
+         "No selectable accessible for " + id);
+
+      testSelectable(id,
                      ["grid2_colhead1", "grid2_colhead2", "grid2_colhead3",
                       "grid2_rowhead", "grid2_cell1", "grid2_cell2"]);
 
       SimpleTest.finish();
     }
 
     SimpleTest.waitForExplicitFinish();
     addA11yLoadEvent(doTest);
@@ -81,34 +139,39 @@
      title="ARIA single selectable widget should implement nsIAccessibleSelectable">
     Mozilla Bug 530014
   </a><br>
   <a target="_blank"
      href="https://bugzilla.mozilla.org/show_bug.cgi?id=566551"
      title="ARIA grid and accessible selectable methods shouldn't use GetNextSibling">
     Mozilla Bug 566551
   </a><br>
+  <a target="_blank"
+     href="https://bugzilla.mozilla.org/show_bug.cgi?id=590176"
+     title="add pseudo SelectAccessible interface">
+    Mozilla Bug 590176
+  </a><br>
   <p id="display"></p>
   <div id="content" style="display: none"></div>
   <pre id="test">
   </pre>
 
   <div role="list" id="list1">
     <div role="listitem">item1</div>
     <div role="listitem">item2</div>
   </div>
 
   <div role="listbox" id="listbox1">
     <div role="listitem">item1</div>
     <div role="listitem">item2</div>
   </div>
 
   <div role="listbox" id="listbox2" aria-multiselectable="true">
-    <div role="listitem">item1</div>
-    <div role="listitem">item2</div>
+    <div role="listitem" id="listbox2_item1">item1</div>
+    <div role="listitem" id="listbox2_item2">item2</div>
   </div>
 
   <div role="grid" id="grid1">
     <div role="row">
       <span role="gridcell">cell</span>
       <span role="gridcell">cell</span>
     </div>
     <div role="row">
new file mode 100644
--- /dev/null
+++ b/accessible/tests/mochitest/selectable/test_listbox.xul
@@ -0,0 +1,155 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
+                 type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/a11y/accessible/treeview.css"
+                 type="text/css"?>
+
+<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+        title="XUL tree selectable tests">
+
+  <script type="application/javascript" 
+          src="chrome://mochikit/content/MochiKit/packed.js" />
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
+
+  <script type="application/javascript"
+          src="../common.js" />
+  <script type="application/javascript"
+          src="../role.js" />
+  <script type="application/javascript"
+          src="../states.js" />
+  <script type="application/javascript"
+          src="../selectable.js" />
+
+  <script type="application/javascript">
+  <![CDATA[
+
+    ////////////////////////////////////////////////////////////////////////////
+    // Test
+
+    //gA11yEventDumpID = "debug";
+
+    var gQueue = null;
+
+    function doTest()
+    {
+      //////////////////////////////////////////////////////////////////////////
+      // single selectable listbox
+
+      var id = "listbox";
+      ok(isAccessible(id, [nsIAccessibleSelectable]),
+         "No selectable accessible for list of " + id);
+
+      var select = getAccessible(id, [nsIAccessibleSelectable]);
+      testSelectableSelection(select, [ ]);
+
+      select.addChildToSelection(1);
+      testSelectableSelection(select, [ "lb1_item2" ], "addChildToSelect(1): ");
+
+      select.removeChildFromSelection(1);
+      testSelectableSelection(select, [ ],
+                              "removeChildFromSelection(1): ");
+
+      todo(select.selectAllSelection() == false,
+           "No way to select all items in listbox '" + id + "'");
+      testSelectableSelection(select, [ "lb1_item1" ], "selectAllSelection: ");
+
+      select.addChildToSelection(1);
+      select.clearSelection();
+      testSelectableSelection(select, [ ], "clearSelection: ");
+
+      //////////////////////////////////////////////////////////////////////////
+      // multiple selectable listbox
+
+      var id = "listbox2";
+      ok(isAccessible(id, [nsIAccessibleSelectable]),
+         "No selectable accessible for list of " + id);
+
+      var select = getAccessible(id, [nsIAccessibleSelectable]);
+      testSelectableSelection(select, [ ]);
+
+      select.addChildToSelection(1);
+      testSelectableSelection(select, [ "lb2_item2" ], "addChildToSelect(1): ");
+
+      select.removeChildFromSelection(1);
+      testSelectableSelection(select, [ ],
+                              "removeChildFromSelection(1): ");
+
+      is(select.selectAllSelection(), true,
+         "All items should be selected in listbox '" + id + "'");
+      testSelectableSelection(select, [ "lb2_item1", "lb2_item2" ],
+                              "selectAllSelection: ");
+
+      select.clearSelection();
+      testSelectableSelection(select, [ ], "clearSelection: ");
+
+      //////////////////////////////////////////////////////////////////////////
+      // listbox with headers
+
+      // XXX: addChildToSelection/removeChildFromSelection don't work correctly
+      // on listboxes with headers because header is inserted into hierarchy
+      // and child indexes that are used in these methods are shifted (see bug
+      // 591939).
+      todo(false,
+           "Fix addChildToSelection/removeChildFromSelection on listboxes with headers.");
+
+      SimpleTest.finish();
+    }
+
+    SimpleTest.waitForExplicitFinish();
+    addA11yLoadEvent(doTest);
+  ]]>
+  </script>
+
+  <hbox flex="1" style="overflow: auto;">
+    <body xmlns="http://www.w3.org/1999/xhtml">
+      <a target="_blank"
+        href="https://bugzilla.mozilla.org/show_bug.cgi?id=590176"
+        title="add pseudo SelectAccessible interface">
+       Mozilla Bug 590176
+      </a><br/>
+      <p id="display"></p>
+      <div id="content" style="display: none">
+      </div>
+      <pre id="test">
+      </pre>
+    </body>
+
+    <vbox flex="1">
+      <listbox id="listbox">
+        <listcols>
+          <listcol flex="1"/>
+          <listcol flex="1"/>
+        </listcols>
+        <listitem id="lb1_item1">
+          <listcell label="cell0"/>
+          <listcell label="cell1"/>
+        </listitem>
+        <listitem id="lb1_item2">
+          <listcell label="cell3"/>
+          <listcell label="cell4"/>
+        </listitem>
+      </listbox>
+
+      <listbox id="listbox2" seltype="multiple">
+        <listcols>
+          <listcol flex="1"/>
+          <listcol flex="1"/>
+        </listcols>
+        <listitem id="lb2_item1">
+          <listcell label="cell0"/>
+          <listcell label="cell1"/>
+        </listitem>
+        <listitem id="lb2_item2">
+          <listcell label="cell3"/>
+          <listcell label="cell4"/>
+        </listitem>
+      </listbox>
+
+      <vbox id="debug"/>
+    </vbox>
+  </hbox>
+
+</window>
+
new file mode 100644
--- /dev/null
+++ b/accessible/tests/mochitest/selectable/test_menu.xul
@@ -0,0 +1,81 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
+                 type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/a11y/accessible/treeview.css"
+                 type="text/css"?>
+
+<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+        title="XUL tree selectable tests">
+
+  <script type="application/javascript" 
+          src="chrome://mochikit/content/MochiKit/packed.js" />
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
+
+  <script type="application/javascript"
+          src="../common.js" />
+  <script type="application/javascript"
+          src="../role.js" />
+  <script type="application/javascript"
+          src="../states.js" />
+  <script type="application/javascript"
+          src="../selectable.js" />
+
+  <script type="application/javascript">
+  <![CDATA[
+
+    ////////////////////////////////////////////////////////////////////////////
+    // Test
+
+    //gA11yEventDumpID = "debug";
+
+    var gQueue = null;
+
+    function doTest()
+    {
+      //////////////////////////////////////////////////////////////////////////
+      // menu
+
+      var id = "menu";
+      var menu = getAccessible("menu");
+      var menuList = menu.firstChild;
+      todo(isAccessible(menuList, [nsIAccessibleSelectable]),
+           "No selectable accessible for list of menu '" + id + "'");
+
+      SimpleTest.finish();
+    }
+
+    SimpleTest.waitForExplicitFinish();
+    addA11yLoadEvent(doTest);
+  ]]>
+  </script>
+
+  <hbox flex="1" style="overflow: auto;">
+    <body xmlns="http://www.w3.org/1999/xhtml">
+      <a target="_blank"
+        href="https://bugzilla.mozilla.org/show_bug.cgi?id=590176"
+        title="add pseudo SelectAccessible interface">
+       Mozilla Bug 590176
+      </a><br/>
+      <p id="display"></p>
+      <div id="content" style="display: none">
+      </div>
+      <pre id="test">
+      </pre>
+    </body>
+
+    <vbox flex="1">
+      <menu label="menu" id="menu">
+        <menupopup>
+          <menuitem label="item1" id="m_item1"/>
+          <menuitem label="item2" id="m_item2"/>
+        </menupopup>
+      </menu>
+
+      <vbox id="debug"/>
+    </vbox>
+  </hbox>
+
+</window>
+
new file mode 100644
--- /dev/null
+++ b/accessible/tests/mochitest/selectable/test_menulist.xul
@@ -0,0 +1,99 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
+                 type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/a11y/accessible/treeview.css"
+                 type="text/css"?>
+
+<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+        title="XUL tree selectable tests">
+
+  <script type="application/javascript" 
+          src="chrome://mochikit/content/MochiKit/packed.js" />
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
+
+  <script type="application/javascript"
+          src="../common.js" />
+  <script type="application/javascript"
+          src="../role.js" />
+  <script type="application/javascript"
+          src="../states.js" />
+  <script type="application/javascript"
+          src="../selectable.js" />
+
+  <script type="application/javascript">
+  <![CDATA[
+
+    ////////////////////////////////////////////////////////////////////////////
+    // Test
+
+    //gA11yEventDumpID = "debug";
+
+    var gQueue = null;
+
+    function doTest()
+    {
+      //////////////////////////////////////////////////////////////////////////
+      // menulist aka combobox
+
+      var id = "combobox";
+      var combobox = getAccessible(id);
+      var comboboxList = combobox.firstChild;
+      ok(isAccessible(comboboxList, [nsIAccessibleSelectable]),
+         "No selectable accessible for list of " + id);
+
+      var select = getAccessible(comboboxList, [nsIAccessibleSelectable]);
+      testSelectableSelection(select, [ "cb1_item1" ]);
+
+      select.addChildToSelection(1);
+      testSelectableSelection(select, [ "cb1_item2" ], "addChildToSelect(1): ");
+
+      select.removeChildFromSelection(1);
+      testSelectableSelection(select, [ ],
+                              "removeChildFromSelection(1): ");
+
+      is(select.selectAllSelection(), false,
+         "No way to select all items in combobox '" + id + "'");
+      testSelectableSelection(select, [ ], "selectAllSelection: ");
+
+      select.addChildToSelection(1);
+      select.clearSelection();
+      testSelectableSelection(select, [ ], "clearSelection: ");
+
+      SimpleTest.finish();
+    }
+
+    SimpleTest.waitForExplicitFinish();
+    addA11yLoadEvent(doTest);
+  ]]>
+  </script>
+
+  <hbox flex="1" style="overflow: auto;">
+    <body xmlns="http://www.w3.org/1999/xhtml">
+      <a target="_blank"
+        href="https://bugzilla.mozilla.org/show_bug.cgi?id=590176"
+        title="add pseudo SelectAccessible interface">
+       Mozilla Bug 590176
+      </a><br/>
+      <p id="display"></p>
+      <div id="content" style="display: none">
+      </div>
+      <pre id="test">
+      </pre>
+    </body>
+
+    <vbox flex="1">
+      <menulist id="combobox">
+        <menupopup>
+          <menuitem id="cb1_item1" label="item1"/>
+          <menuitem id="cb1_item2" label="item2"/>
+        </menupopup>
+      </menulist>
+
+      <vbox id="debug"/>
+    </vbox>
+  </hbox>
+
+</window>
+
--- a/accessible/tests/mochitest/selectable/test_select.html
+++ b/accessible/tests/mochitest/selectable/test_select.html
@@ -12,55 +12,234 @@
           src="chrome://mochikit/content/MochiKit/packed.js"></script>
   <script type="application/javascript"
           src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
 
   <script type="application/javascript"
           src="../common.js"></script>
   <script type="application/javascript"
           src="../role.js"></script>
+  <script type="application/javascript"
+          src="../states.js"></script>
+  <script type="application/javascript"
+          src="../selectable.js"></script>
 
   <script type="application/javascript">
 
     function doTest()
     {
-      var combobox = getAccessible("combobox");
+      //////////////////////////////////////////////////////////////////////////
+      // select@size="1" aka combobox
+
+      var id = "combobox";
+      var combobox = getAccessible(id);
       var comboboxList = combobox.firstChild;
       ok(isAccessible(comboboxList, [nsIAccessibleSelectable]),
          "No selectable accessible for list of " + id);
 
+      var select = getAccessible(comboboxList, [nsIAccessibleSelectable]);
+      testSelectableSelection(select, [ "cb1_item1" ]);
+
+      // select 2nd item
+      select.addChildToSelection(1);
+      testSelectableSelection(select, [ "cb1_item2" ], "addChildToSelect(1): ");
+
+      // unselect 2nd item, 1st item gets selected automatically
+      select.removeChildFromSelection(1);
+      testSelectableSelection(select, [ "cb1_item1" ],
+                              "removeChildFromSelection(1): ");
+
+      // doesn't change selection
+      is(select.selectAllSelection(), false,
+         "No way to select all items in combobox '" + id + "'");
+      testSelectableSelection(select, [ "cb1_item1" ], "selectAllSelection: ");
+
+      // doesn't change selection
+      select.clearSelection();
+      testSelectableSelection(select, [ "cb1_item1" ], "clearSelection: ");
+
+      //////////////////////////////////////////////////////////////////////////
+      // select@size="1" with optgroups
+
+      id = "combobox2";
+      combobox = getAccessible(id);
+      comboboxList = combobox.firstChild;
+      ok(isAccessible(comboboxList, [nsIAccessibleSelectable]),
+         "No selectable accessible for list of " + id);
+
+      select = getAccessible(comboboxList, [nsIAccessibleSelectable]);
+      testSelectableSelection(select, [ "cb2_item1" ]);
+
+      select.addChildToSelection(1);
+      testSelectableSelection(select, [ "cb2_item2" ]);
+
+      select.removeChildFromSelection(1);
+      testSelectableSelection(select, [ "cb2_item1" ]);
+
+      is(select.selectAllSelection(), false,
+         "No way to select all items in combobox " + id + "'");
+      testSelectableSelection(select, [ "cb2_item1" ]);
+
+      select.clearSelection();
+      testSelectableSelection(select, [ "cb2_item1" ]);
+
+      //////////////////////////////////////////////////////////////////////////
+      // select@size="4" aka single selectable listbox
+
       var id = "listbox";
       ok(isAccessible(id, [nsIAccessibleSelectable]),
          "No selectable accessible for " + id);
 
+      select = getAccessible(id, [nsIAccessibleSelectable]);
+      testSelectableSelection(select, [ ]);
+
+      // select 2nd item
+      select.addChildToSelection(1);
+      testSelectableSelection(select, [ "lb1_item2" ], "addChildToSelect(1): ");
+
+      // unselect 2nd item, 1st item gets selected automatically
+      select.removeChildFromSelection(1);
+      testSelectableSelection(select, [ ],
+                              "removeChildFromSelection(1): ");
+
+      // doesn't change selection
+      is(select.selectAllSelection(), false,
+         "No way to select all items in single selectable listbox '" + id + "'");
+      testSelectableSelection(select, [ ], "selectAllSelection: ");
+
+      // doesn't change selection
+      select.clearSelection();
+      testSelectableSelection(select, [ ], "clearSelection: ");
+
+      //////////////////////////////////////////////////////////////////////////
+      // select@size="4" with optgroups, single selectable
+
+      id = "listbox2";
+      ok(isAccessible(id, [nsIAccessibleSelectable]),
+         "No selectable accessible for " + id);
+
+      select = getAccessible(id, [nsIAccessibleSelectable]);
+      testSelectableSelection(select, [ ]);
+
+      select.addChildToSelection(1);
+      testSelectableSelection(select, [ "lb2_item2" ]);
+
+      select.removeChildFromSelection(1);
+      testSelectableSelection(select, [ ]);
+
+      is(select.selectAllSelection(), false,
+         "No way to select all items in single selectable listbox " + id + "'");
+      testSelectableSelection(select, [ ]);
+
+      select.clearSelection();
+      testSelectableSelection(select, [ ]);
+
+      //////////////////////////////////////////////////////////////////////////
+      // select@size="4" multiselect aka listbox
+
+      id = "listbox3";
+      ok(isAccessible(id, [nsIAccessibleSelectable]),
+         "No selectable accessible for " + id);
+
+      select = getAccessible(id, [nsIAccessibleSelectable]);
+      testSelectableSelection(select, [ ]);
+
+      select.addChildToSelection(0);
+      testSelectableSelection(select, [ "lb3_item1" ], "addChildToSelection: ");
+
+      select.removeChildFromSelection(0);
+      testSelectableSelection(select, [ ], "removeChildFromSelection: ");
+
+      is(select.selectAllSelection(), true,
+         "All items in listbox '" + id + "' should be selected");
+      testSelectableSelection(select, [ "lb3_item1", "lb3_item2"],
+                              "selectAllSelection: ");
+
+      select.clearSelection();
+      testSelectableSelection(select, [ ], "clearSelection: ");
+
+      //////////////////////////////////////////////////////////////////////////
+      // select@size="4" multiselect with optgroups
+
+      var id = "listbox4";
+      ok(isAccessible(id, [nsIAccessibleSelectable]),
+         "No selectable accessible for " + id);
+
+      select = getAccessible(id, [nsIAccessibleSelectable]);
+      testSelectableSelection(select, [ ]);
+
+      select.addChildToSelection(0);
+      testSelectableSelection(select, [ "lb4_item1" ]);
+
+      select.removeChildFromSelection(0);
+      testSelectableSelection(select, [ ]);
+
+      is(select.selectAllSelection(), true,
+         "All items in listbox '" + id + "' should be selected");
+      testSelectableSelection(select, [ "lb4_item1", "lb4_item2"]);
+
+      select.clearSelection();
+      testSelectableSelection(select, [ ]);
+
       SimpleTest.finish();
     }
 
     SimpleTest.waitForExplicitFinish();
     addA11yLoadEvent(doTest);
   </script>
 
 </head>
 
 <body>
 
   <a target="_blank"
      href="https://bugzilla.mozilla.org/show_bug.cgi?id=530014"
      title="ARIA single selectable widget should implement nsIAccessibleSelectable">
     Mozilla Bug 530014
   </a><br>
+  <a target="_blank"
+     href="https://bugzilla.mozilla.org/show_bug.cgi?id=590176"
+     title="add pseudo SelectAccessible interface">
+    Mozilla Bug 590176
+  </a><br>
   <p id="display"></p>
   <div id="content" style="display: none"></div>
   <pre id="test">
   </pre>
 
   <select id="combobox">
-    <option>option</option>
-    <option>option</option>
+    <option id="cb1_item1">option1</option>
+    <option id="cb1_item2">option2</option>
+  </select>
+
+  <select id="combobox2">
+    <option id="cb2_item1">option1</option>
+    <optgroup>optgroup
+      <option id="cb2_item2">option2</option>
+    </optgroup>
   </select>
 
   <select id="listbox" size="4">
-    <option>option</option>
-    <option>option</option>
+    <option id="lb1_item1">option1</option>
+    <option id="lb1_item2">option2</option>
+  </select>
+
+  <select id="listbox2" size="4">
+    <option id="lb2_item1">option1</option>
+    <optgroup>optgroup>
+      <option id="lb2_item2">option2</option>
+    </optgroup>
+  </select>
+
+  <select id="listbox3" size="4" multiple="true">
+    <option id="lb3_item1">option1</option>
+    <option id="lb3_item2">option2</option>
+  </select>
+
+  <select id="listbox4" size="4" multiple="true">
+    <option id="lb4_item1">option1</option>
+    <optgroup>optgroup>
+      <option id="lb4_item2">option2</option>
+    </optgroup>
   </select>
 
 </body>
 </html>