Bug 365973 - cant expose <listbox> with multiple columns, r=evan.yan, a=mtschrep
authorsurkov.alexander@gmail.com
Tue, 19 Feb 2008 01:07:35 -0800
changeset 11854 54b053f2f2e9721dceeb67406366fb676a1d8595
parent 11853 fd041ebe568043808079941a082958642df1f404
child 11855 c2925228a4b212f07411a682c12d90dbfe5e8805
push id1
push userbsmedberg@mozilla.com
push dateThu, 20 Mar 2008 16:49:24 +0000
treeherdermozilla-central@61007906a1f8 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersevan.yan, mtschrep
bugs365973
milestone1.9b4pre
Bug 365973 - cant expose <listbox> with multiple columns, r=evan.yan, a=mtschrep
accessible/public/nsIAccessibleProvider.idl
accessible/src/base/nsAccessibilityAtomList.h
accessible/src/base/nsAccessibilityService.cpp
accessible/src/base/nsAccessibilityService.h
accessible/src/xul/nsXULSelectAccessible.cpp
accessible/src/xul/nsXULSelectAccessible.h
toolkit/content/widgets/listbox.xml
--- a/accessible/public/nsIAccessibleProvider.idl
+++ b/accessible/public/nsIAccessibleProvider.idl
@@ -72,19 +72,20 @@ interface nsIAccessibleProvider : nsISup
   const long XULColorPicker = 0x00001004;
   const long XULColorPickerTile = 0x00001005;
   const long XULCombobox = 0x00001006;
   const long XULDropmarker = 0x00001007;
   const long XULGroupbox = 0x00001008;
   const long XULImage = 0x00001009;
   const long XULLink = 0x0000100A;
   const long XULListbox = 0x0000100B;
-  const long XULListitem = 0x0000100C;
+  const long XULListCell = 0x00001026;
   const long XULListHead = 0x00001024;
   const long XULListHeader = 0x00001025;
+  const long XULListitem = 0x0000100C;
   const long XULMenubar = 0x0000100D;
   const long XULMenuitem = 0x0000100E;
   const long XULMenupopup = 0x0000100F;
   const long XULMenuSeparator = 0x00001010;
   const long XULPane    = 0x00001011;
   const long XULProgressMeter = 0x00001012;
   const long XULScale = 0x00001013;
   const long XULStatusBar = 0x00001014;
--- a/accessible/src/base/nsAccessibilityAtomList.h
+++ b/accessible/src/base/nsAccessibilityAtomList.h
@@ -111,16 +111,18 @@ ACCESSIBILITY_ATOM(h6, "h6")
 ACCESSIBILITY_ATOM(item, "item") // XForms
 ACCESSIBILITY_ATOM(itemset, "itemset") // XForms
 ACCESSIBILITY_ATOM(img, "img")
 ACCESSIBILITY_ATOM(input, "input")
 ACCESSIBILITY_ATOM(label, "label")
 ACCESSIBILITY_ATOM(legend, "legend")
 ACCESSIBILITY_ATOM(li, "li")
 ACCESSIBILITY_ATOM(link, "link")
+ACCESSIBILITY_ATOM(listhead, "listhead") // XUL
+ACCESSIBILITY_ATOM(listheader, "listheader") // XUL
 ACCESSIBILITY_ATOM(map, "map")
 ACCESSIBILITY_ATOM(math, "math")
 ACCESSIBILITY_ATOM(menu, "menu")    // XUL
 ACCESSIBILITY_ATOM(menupopup, "menupopup")     // XUL
 ACCESSIBILITY_ATOM(object, "object")
 ACCESSIBILITY_ATOM(ol, "ol")
 ACCESSIBILITY_ATOM(optgroup, "optgroup")
 ACCESSIBILITY_ATOM(option, "option")
--- a/accessible/src/base/nsAccessibilityService.cpp
+++ b/accessible/src/base/nsAccessibilityService.cpp
@@ -1693,16 +1693,19 @@ nsresult nsAccessibilityService::GetAcce
       break;
     }
     case nsIAccessibleProvider::XULLink:
       *aAccessible = new nsXULLinkAccessible(aNode, weakShell);
       break;
     case nsIAccessibleProvider::XULListbox:
       *aAccessible = new nsXULListboxAccessible(aNode, weakShell);
       break;
+    case nsIAccessibleProvider::XULListCell:
+      *aAccessible = new nsXULListCellAccessible(aNode, weakShell);
+      break;
     case nsIAccessibleProvider::XULListHead:
       *aAccessible = new nsXULColumnsAccessible(aNode, weakShell);
       break;
     case nsIAccessibleProvider::XULListHeader:
       *aAccessible = new nsXULColumnItemAccessible(aNode, weakShell);
       break;
     case nsIAccessibleProvider::XULListitem:
       *aAccessible = new nsXULListitemAccessible(aNode, weakShell);
--- a/accessible/src/base/nsAccessibilityService.h
+++ b/accessible/src/base/nsAccessibilityService.h
@@ -253,17 +253,21 @@ static const char kRoleNames[][20] = {
   "redundant object",    //ROLE_REDUNDANT_OBJECT
   "form",                //ROLE_FORM
   "ime",                 //ROLE_IME
   "app root",            //ROLE_APP_ROOT
   "parent menuitem",     //ROLE_PARENT_MENUITEM
   "calendar",            //ROLE_CALENDAR
   "combobox list",       //ROLE_COMBOBOX_LIST
   "combobox option",     //ROLE_COMBOBOX_OPTION
-  "image map"            //ROLE_IMAGE_MAP
+  "image map",           //ROLE_IMAGE_MAP
+  "listbox option",      //ROLE_OPTION
+  "listbox rich option", //ROLE_RICH_OPTION
+  "listbox"              //ROLE_LISTBOX
+  
 };
 
 /**
  * Map nsIAccessibleEvents constants to strings. Used by
  * nsIAccessibleRetrieval::getStringEventType() method.
  */
 static const char kEventTypeNames[][40] = {
   "unknown",                                 //
--- a/accessible/src/xul/nsXULSelectAccessible.cpp
+++ b/accessible/src/xul/nsXULSelectAccessible.cpp
@@ -139,31 +139,63 @@ nsXULColumnItemAccessible::DoAction(PRUi
     return NS_ERROR_INVALID_ARG;
 
   return DoCommand();
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsXULListboxAccessible
 
-/** Constructor */
-nsXULListboxAccessible::nsXULListboxAccessible(nsIDOMNode* aDOMNode, nsIWeakReference* aShell):
-nsXULSelectableAccessible(aDOMNode, aShell)
+nsXULListboxAccessible::
+  nsXULListboxAccessible(nsIDOMNode* aDOMNode, nsIWeakReference* aShell) :
+  nsXULSelectableAccessible(aDOMNode, aShell)
 {
 }
 
-/**
-  * As a nsXULListboxAccessible we can have the following states:
-  *     nsIAccessibleStates::STATE_FOCUSED
-  *     nsIAccessibleStates::STATE_READONLY
-  *     nsIAccessibleStates::STATE_FOCUSABLE
-  */
+NS_IMPL_ADDREF_INHERITED(nsXULListboxAccessible, nsXULSelectableAccessible)
+NS_IMPL_RELEASE_INHERITED(nsXULListboxAccessible, nsXULSelectableAccessible)
+
+nsresult
+nsXULListboxAccessible::QueryInterface(REFNSIID aIID, void** aInstancePtr)
+{
+  nsresult rv = nsXULSelectableAccessible::QueryInterface(aIID, aInstancePtr);
+  if (*aInstancePtr)
+    return rv;
+
+  if (aIID.Equals(NS_GET_IID(nsIAccessibleTable)) && IsTree()) {
+    *aInstancePtr = static_cast<nsIAccessibleTable*>(this);
+    NS_ADDREF_THIS();
+    return NS_OK;
+  }
+
+  return NS_ERROR_NO_INTERFACE;
+}
+
+PRBool
+nsXULListboxAccessible::IsTree()
+{
+  PRInt32 numColumns = 0;
+  nsresult rv = GetColumns(&numColumns);
+  if (NS_FAILED(rv))
+    return PR_FALSE;
+  
+  return numColumns > 1;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// nsXULListboxAccessible. nsIAccessible
+
 NS_IMETHODIMP
 nsXULListboxAccessible::GetState(PRUint32 *aState, PRUint32 *aExtraState)
 {
+  // As a nsXULListboxAccessible we can have the following states:
+  //   STATE_FOCUSED
+  //   STATE_READONLY
+  //   STATE_FOCUSABLE
+
   // Get focus status from base class
   nsresult rv = nsAccessible::GetState(aState, aExtraState);
   NS_ENSURE_SUCCESS(rv, rv);
   if (!mDOMNode) {
     return NS_OK;
   }
 
 // see if we are multiple select if so set ourselves as such
@@ -203,39 +235,389 @@ NS_IMETHODIMP nsXULListboxAccessible::Ge
     // and has a parent popup <panel>
     nsCOMPtr<nsIDOMXULPopupElement> xulPopup =
       do_QueryInterface(content->GetParent());
     if (xulPopup) {
       *aRole = nsIAccessibleRole::ROLE_COMBOBOX_LIST;
       return NS_OK;
     }
   }
-  *aRole = nsIAccessibleRole::ROLE_LIST;
+
+  if (IsTree())
+    *aRole = nsIAccessibleRole::ROLE_TABLE;
+  else
+    *aRole = nsIAccessibleRole::ROLE_LISTBOX;
+
+  return NS_OK;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// nsXULListboxAccessible. nsIAccessibleTable
+
+NS_IMETHODIMP
+nsXULListboxAccessible::GetCaption(nsIAccessible **aCaption)
+{
+  NS_ENSURE_ARG_POINTER(aCaption);
+  *aCaption = nsnull;
+
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+nsXULListboxAccessible::GetSummary(nsAString &aSummary)
+{
+  aSummary.Truncate();
+
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+nsXULListboxAccessible::GetColumns(PRInt32 *aNumColumns)
+{
+  NS_ENSURE_ARG_POINTER(aNumColumns);
+  *aNumColumns = 0;
+
+  if (!mDOMNode)
+    return NS_ERROR_FAILURE;
+
+  nsCOMPtr<nsIContent> content(do_QueryInterface(mDOMNode));
+
+  nsCOMPtr<nsIContent> headContent;
+  PRUint32 count = content->GetChildCount();
+
+  for (PRUint32 index = 0; index < count; ++index) {
+    nsCOMPtr<nsIContent> childContent(content->GetChildAt(index));
+    NS_ENSURE_STATE(childContent);
+
+    if (childContent->NodeInfo()->Equals(nsAccessibilityAtoms::listhead,
+                                         kNameSpaceID_XUL)) {
+      headContent = childContent;
+    }
+  }
+
+  if (!headContent)
+    return NS_OK;
+
+  PRUint32 columnCount = 0;
+  count = headContent->GetChildCount();
+
+  for (PRUint32 index = 0; index < count; ++index) {
+    nsCOMPtr<nsIContent> childContent(headContent->GetChildAt(index));
+    NS_ENSURE_STATE(childContent);
+
+    if (childContent->NodeInfo()->Equals(nsAccessibilityAtoms::listheader,
+                                         kNameSpaceID_XUL)) {
+      columnCount++;
+    }
+  }
+
+  *aNumColumns = columnCount;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXULListboxAccessible::GetColumnHeader(nsIAccessibleTable **aColumnHeader)
+{
+  NS_ENSURE_ARG_POINTER(aColumnHeader);
+  *aColumnHeader = nsnull;
+
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+nsXULListboxAccessible::GetRows(PRInt32 *aNumRows)
+{
+  NS_ENSURE_ARG_POINTER(aNumRows);
+  *aNumRows = 0;
+
+  if (!mDOMNode)
+    return NS_ERROR_FAILURE;
+
+  nsCOMPtr<nsIDOMXULSelectControlElement> element(do_QueryInterface(mDOMNode));
+  NS_ENSURE_STATE(element);
+
+  PRUint32 itemCount = 0;
+  nsresult rv = element->GetItemCount(&itemCount);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  *aNumRows = itemCount;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXULListboxAccessible::GetRowHeader(nsIAccessibleTable **aRowHeader)
+{
+  NS_ENSURE_ARG_POINTER(aRowHeader);
+  *aRowHeader = nsnull;
+
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+nsXULListboxAccessible::CellRefAt(PRInt32 aRow, PRInt32 aColumn,
+                                  nsIAccessible **aAccessibleCell)
+{
+  NS_ENSURE_ARG_POINTER(aAccessibleCell);
+  *aAccessibleCell = nsnull;
+
+  if (IsDefunct())
+    return NS_OK;
+
+  nsCOMPtr<nsIDOMXULSelectControlElement> control =
+    do_QueryInterface(mDOMNode);
+
+  nsCOMPtr<nsIDOMXULSelectControlItemElement> item;
+  control->GetItemAtIndex(aRow, getter_AddRefs(item));
+  NS_ENSURE_TRUE(item, NS_ERROR_INVALID_ARG);
+
+  nsCOMPtr<nsIAccessible> accessibleRow;
+  GetAccService()->GetAccessibleInWeakShell(item, mWeakShell,
+                                            getter_AddRefs(accessibleRow));
+  NS_ENSURE_STATE(accessibleRow);
+
+  nsresult rv = accessibleRow->GetChildAt(aColumn, aAccessibleCell);
+  NS_ENSURE_SUCCESS(rv, NS_ERROR_INVALID_ARG);
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXULListboxAccessible::GetIndexAt(PRInt32 aRow, PRInt32 aColumn,
+                                   PRInt32 *aIndex)
+{
+  NS_ENSURE_ARG_POINTER(aIndex);
+  *aIndex = -1;
+
+  PRInt32 rowCount = 0;
+  nsresult rv = GetRows(&rowCount);
+  NS_ENSURE_SUCCESS(rv, rv);
+  NS_ENSURE_TRUE(0 <= aRow && aRow <= rowCount, NS_ERROR_INVALID_ARG);
+
+  PRInt32 columnCount = 0;
+  rv = GetColumns(&columnCount);
+  NS_ENSURE_SUCCESS(rv, rv);
+  NS_ENSURE_TRUE(0 <= aColumn && aColumn <= columnCount, NS_ERROR_INVALID_ARG);
+
+  *aIndex = aRow * columnCount + aColumn;
   return NS_OK;
 }
 
-/** ----- nsXULListitemAccessible ----- */
+NS_IMETHODIMP
+nsXULListboxAccessible::GetColumnAtIndex(PRInt32 aIndex, PRInt32 *aColumn)
+{
+  NS_ENSURE_ARG_POINTER(aColumn);
+  *aColumn = -1;
+
+  PRInt32 columnCount = 0;
+  nsresult rv = GetColumns(&columnCount);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  *aColumn = aIndex % columnCount;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXULListboxAccessible::GetRowAtIndex(PRInt32 aIndex, PRInt32 *aRow)
+{
+  NS_ENSURE_ARG_POINTER(aRow);
+  *aRow = -1;
+
+  PRInt32 columnCount = 0;
+  nsresult rv = GetColumns(&columnCount);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  *aRow = aIndex / columnCount;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXULListboxAccessible::GetColumnExtentAt(PRInt32 aRow, PRInt32 aColumn,
+                                          PRInt32 *aCellSpans)
+{
+  NS_ENSURE_ARG_POINTER(aCellSpans);
+  *aCellSpans = 1;
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXULListboxAccessible::GetRowExtentAt(PRInt32 aRow, PRInt32 aColumn,
+                                       PRInt32 *aCellSpans)
+{
+  NS_ENSURE_ARG_POINTER(aCellSpans);
+  *aCellSpans = 1;
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXULListboxAccessible::GetColumnDescription(PRInt32 aColumn,
+                                             nsAString& aDescription)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+nsXULListboxAccessible::GetRowDescription(PRInt32 aRow, nsAString& aDescription)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+nsXULListboxAccessible::IsColumnSelected(PRInt32 aColumn, PRBool *aIsSelected)
+{
+  NS_ENSURE_ARG_POINTER(aIsSelected);
+
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+nsXULListboxAccessible::IsRowSelected(PRInt32 aRow, PRBool *aIsSelected)
+{
+  NS_ENSURE_ARG_POINTER(aIsSelected);
+
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+nsXULListboxAccessible::IsCellSelected(PRInt32 aRow, PRInt32 aColumn,
+                                       PRBool *aIsSelected)
+{
+  NS_ENSURE_ARG_POINTER(aIsSelected);
+
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
 
-/** Constructor */
-nsXULListitemAccessible::nsXULListitemAccessible(nsIDOMNode* aDOMNode, nsIWeakReference* aShell):
-nsXULMenuitemAccessible(aDOMNode, aShell)
+NS_IMETHODIMP
+nsXULListboxAccessible::GetSelectedCellsCount(PRUint32* aCount)
+{
+  NS_ENSURE_ARG_POINTER(aCount);
+
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+nsXULListboxAccessible::GetSelectedColumnsCount(PRUint32* aCount)
+{
+  NS_ENSURE_ARG_POINTER(aCount);
+
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+nsXULListboxAccessible::GetSelectedRowsCount(PRUint32* aCount)
+{
+  NS_ENSURE_ARG_POINTER(aCount);
+
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+nsXULListboxAccessible::GetSelectedCells(PRUint32 *aNumCells, PRInt32 **aCells)
+{
+  NS_ENSURE_ARG_POINTER(aNumCells);
+  NS_ENSURE_ARG_POINTER(aCells);
+
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+nsXULListboxAccessible::GetSelectedColumns(PRUint32 *aNumColumns,
+                                           PRInt32 **aColumns)
+{
+  NS_ENSURE_ARG_POINTER(aNumColumns);
+  NS_ENSURE_ARG_POINTER(aColumns);
+
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+nsXULListboxAccessible::GetSelectedRows(PRUint32 *aNumRows, PRInt32 **aRows)
+{
+  NS_ENSURE_ARG_POINTER(aNumRows);
+  NS_ENSURE_ARG_POINTER(aRows);
+
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+nsXULListboxAccessible::SelectRow(PRInt32 aRow)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+nsXULListboxAccessible::SelectColumn(PRInt32 aColumn)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+nsXULListboxAccessible::UnselectRow(PRInt32 aRow)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+nsXULListboxAccessible::UnselectColumn(PRInt32 aColumn)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+nsXULListboxAccessible::IsProbablyForLayout(PRBool *aIsProbablyForLayout)
+{
+  NS_ENSURE_ARG_POINTER(aIsProbablyForLayout);
+  *aIsProbablyForLayout = PR_FALSE;
+
+  return NS_OK;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// nsXULListitemAccessible
+
+nsXULListitemAccessible::
+  nsXULListitemAccessible(nsIDOMNode* aDOMNode, nsIWeakReference* aShell) :
+  nsXULMenuitemAccessible(aDOMNode, aShell)
 {
   mIsCheckbox = PR_FALSE;
   nsCOMPtr<nsIDOMElement> listItem (do_QueryInterface(mDOMNode));
   if (listItem) {
     nsAutoString typeString;
     nsresult res = listItem->GetAttribute(NS_LITERAL_STRING("type"), typeString);
     if (NS_SUCCEEDED(res) && typeString.Equals(NS_LITERAL_STRING("checkbox")))
       mIsCheckbox = PR_TRUE;
   }
 }
 
 /** Inherit the ISupports impl from nsAccessible, we handle nsIAccessibleSelectable */
 NS_IMPL_ISUPPORTS_INHERITED0(nsXULListitemAccessible, nsAccessible)
 
+already_AddRefed<nsIAccessible>
+nsXULListitemAccessible::GetListAccessible()
+{
+  if (IsDefunct())
+    return nsnull;
+  
+  nsCOMPtr<nsIDOMXULSelectControlItemElement> listItem =
+    do_QueryInterface(mDOMNode);
+  
+  nsCOMPtr<nsIDOMXULSelectControlElement> list;
+  listItem->GetControl(getter_AddRefs(list));
+  if (!list)
+    return nsnull;
+
+  nsIAccessible *listAcc = nsnull;
+  GetAccService()->GetAccessibleInWeakShell(list, mWeakShell, &listAcc);
+  return listAcc;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// nsXULListitemAccessible. nsIAccessible
+
 /**
   * If there is a Listcell as a child ( not anonymous ) use it, otherwise
   *   default to getting the name from GetXULName
   */
 NS_IMETHODIMP nsXULListitemAccessible::GetName(nsAString& _retval)
 {
   if (!mDOMNode)
     return NS_ERROR_FAILURE;
@@ -255,16 +637,24 @@ NS_IMETHODIMP nsXULListitemAccessible::G
   return GetXULName(_retval);
 }
 
 /**
   *
   */
 NS_IMETHODIMP nsXULListitemAccessible::GetRole(PRUint32 *aRole)
 {
+  nsCOMPtr<nsIAccessible> listAcc = GetListAccessible();
+  NS_ENSURE_STATE(listAcc);
+
+  if (Role(listAcc) == nsIAccessibleRole::ROLE_TABLE) {
+    *aRole = nsIAccessibleRole::ROLE_ROW;
+    return NS_OK;
+  }
+
   if (mIsCheckbox)
     *aRole = nsIAccessibleRole::ROLE_CHECKBUTTON;
   else if (mParent && Role(mParent) == nsIAccessibleRole::ROLE_COMBOBOX_LIST)
     *aRole = nsIAccessibleRole::ROLE_COMBOBOX_OPTION;
   else
     *aRole = nsIAccessibleRole::ROLE_RICH_OPTION;
   return NS_OK;
 }
@@ -326,16 +716,33 @@ NS_IMETHODIMP nsXULListitemAccessible::G
 NS_IMETHODIMP
 nsXULListitemAccessible::GetAllowsAnonChildAccessibles(PRBool *aAllowsAnonChildren)
 {
   // That indicates we should walk anonymous children for listitems
   *aAllowsAnonChildren = PR_TRUE;
   return NS_OK;
 }
 
+////////////////////////////////////////////////////////////////////////////////
+// nsXULListCellAccessible
+nsXULListCellAccessible::
+  nsXULListCellAccessible(nsIDOMNode* aDOMNode, nsIWeakReference* aShell):
+  nsHyperTextAccessibleWrap(aDOMNode, aShell)
+{
+}
+
+NS_IMETHODIMP
+nsXULListCellAccessible::GetRole(PRUint32 *aRole)
+{
+  NS_ENSURE_ARG_POINTER(aRole);
+
+  *aRole = nsIAccessibleRole::ROLE_CELL;
+  return NS_OK;
+}
+
 /** ------------------------------------------------------ */
 /**  Finally, the Combobox widgets                         */
 /** ------------------------------------------------------ */
 
 /** ----- nsXULComboboxAccessible ----- */
 
 /** Constructor */
 nsXULComboboxAccessible::nsXULComboboxAccessible(nsIDOMNode* aDOMNode, nsIWeakReference* aShell):
--- a/accessible/src/xul/nsXULSelectAccessible.h
+++ b/accessible/src/xul/nsXULSelectAccessible.h
@@ -33,16 +33,18 @@
  * 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 __nsXULSelectAccessible_h__
 #define __nsXULSelectAccessible_h__
 
+#include "nsIAccessibleTable.h"
+
 #include "nsCOMPtr.h"
 #include "nsXULMenuAccessible.h"
 #include "nsBaseWidgetAccessible.h"
 
 class nsIWeakReference;
 
 /**
  * nsXULColumnsAccessible are accessible for list and tree columns elements
@@ -96,27 +98,33 @@ public:
 
 /** ------------------------------------------------------ */
 /**  First, the common widgets                             */
 /** ------------------------------------------------------ */
 
 /*
  * A class the represents the XUL Listbox widget.
  */
-class nsXULListboxAccessible : public nsXULSelectableAccessible
+class nsXULListboxAccessible : public nsXULSelectableAccessible,
+                               public nsIAccessibleTable
 {
 public:
-
   nsXULListboxAccessible(nsIDOMNode* aDOMNode, nsIWeakReference* aShell);
   virtual ~nsXULListboxAccessible() {}
 
-  /* ----- nsIAccessible ----- */
-  NS_IMETHOD GetRole(PRUint32 *_retval);
+  NS_DECL_ISUPPORTS_INHERITED
+  NS_DECL_NSIACCESSIBLETABLE
+
+  // nsIAccessible
+  NS_IMETHOD GetRole(PRUint32 *aRole);
   NS_IMETHOD GetState(PRUint32 *aState, PRUint32 *aExtraState);
-  NS_IMETHOD GetValue(nsAString& _retval);
+  NS_IMETHOD GetValue(nsAString& aValue);
+
+protected:
+  PRBool IsTree();
 };
 
 /**
   * Listitems -- used in listboxes 
   */
 class nsXULListitemAccessible : public nsXULMenuitemAccessible
 {
 public:
@@ -131,20 +139,35 @@ public:
   NS_IMETHOD GetName(nsAString& _retval);
   NS_IMETHOD GetRole(PRUint32 *_retval);
   NS_IMETHOD GetState(PRUint32 *aState, PRUint32 *aExtraState);
   NS_IMETHOD GetActionName(PRUint8 index, nsAString& aName);
   // Don't use XUL menuitems's description attribute
   NS_IMETHOD GetDescription(nsAString& aDesc) { return nsAccessibleWrap::GetDescription(aDesc); }
   NS_IMETHOD GetAllowsAnonChildAccessibles(PRBool *aAllowsAnonChildren);
 
+protected:
+  already_AddRefed<nsIAccessible> GetListAccessible();
+
 private:
   PRBool mIsCheckbox;
 };
 
+/**
+ * Class represents xul:listcell.
+ */
+class nsXULListCellAccessible : public nsHyperTextAccessibleWrap
+{
+public:
+  nsXULListCellAccessible(nsIDOMNode* aDOMNode, nsIWeakReference* aShell);
+
+  // nsIAccessible
+  NS_IMETHOD GetRole(PRUint32 *aRole);
+};
+
 /** ------------------------------------------------------ */
 /**  Finally, the Combobox widgets                         */
 /** ------------------------------------------------------ */
 
 /*
  * A class the represents the XUL Combobox widget.
  */
 class nsXULComboboxAccessible : public nsAccessibleWrap
--- a/toolkit/content/widgets/listbox.xml
+++ b/toolkit/content/widgets/listbox.xml
@@ -1062,16 +1062,48 @@
       <stylesheet src="chrome://global/skin/listbox.css"/>
     </resources>
 
     <content>
       <children>
         <xul:label class="listcell-label" xbl:inherits="value=label,flex=flexlabel,crop,disabled" flex="1" crop="right"/>
       </children>
     </content>
+
+    <implementation implements="nsIAccessibleProvider">
+      <property name="accessibleType" readonly="true">
+        <getter>
+        <![CDATA[
+          // Don't expose xul:listcell as cell accessible until listbox is
+          // multicolumn.
+          const Ci = Components.interfaces;
+          const kNoAccessible = Ci.nsIAccessibleProvider.NoAccessible;
+          const kListCellAccessible = Ci.nsIAccessibleProvider.XULListCell;
+
+          var listitem = this.parentNode;
+          if (!(listitem instanceof Ci.nsIDOMXULSelectControlItemElement))
+            return kNoAccessible;
+
+          var list = listitem.control;
+          if (!list)
+            return kNoAccessible;
+
+          var listhead = list.getElementsByTagName("listhead")[0];
+          if (!listhead)
+            return kNoAccessible;
+
+          var listheaders = listhead.getElementsByTagName("listheader");
+          if (listheaders.length <= 1)
+            return kNoAccessible;
+
+          return kListCellAccessible;
+        ]]>
+        </getter>
+      </property>
+    </implementation>
   </binding>
 
   <binding id="listcell-iconic"
            extends="chrome://global/content/bindings/listbox.xml#listcell">
     <content>
       <children>
         <xul:image class="listcell-icon" xbl:inherits="src=image"/>
         <xul:label class="listcell-label" xbl:inherits="value=label,flex=flexlabel,crop,disabled" flex="1" crop="right"/>