NS_IMETHODIMP
nsARIAGridAccessible::GetSelectedCellIndices(PRUint32 *aCellsCount,
                                             PRInt32 **aCells)
{
  NS_ENSURE_ARG_POINTER(aCellsCount);
  *aCellsCount = 0;
  NS_ENSURE_ARG_POINTER(aCells);
  *aCells = nsnull;

  if (IsDefunct())
    return NS_ERROR_FAILURE;

  PRInt32 rowCount = 0;
  GetRowCount(&rowCount);

  PRInt32 colCount = 0;
  GetColumnCount(&colCount);

  nsTArray<PRInt32> selCells(rowCount * colCount);

  AccIterator rowIter(this, filters::GetRow);

  nsAccessible *row = nsnull;
  for (PRInt32 rowIdx = 0; (row = rowIter.GetNext()); rowIdx++) {
    if (nsAccUtils::IsARIASelected(row)) {
      for (PRInt32 colIdx = 0; colIdx < colCount; colIdx++)
        selCells.AppendElement(rowIdx * colCount + colIdx);

      continue;
    }

    AccIterator cellIter(row, filters::GetCell);
    nsAccessible *cell = nsnull;

    for (PRInt32 colIdx = 0; (cell = cellIter.GetNext()); colIdx++) {
      if (nsAccUtils::IsARIASelected(cell))
        selCells.AppendElement(rowIdx * colCount + colIdx);
    }
  }

  PRUint32 selCellsCount = selCells.Length();
  if (!selCellsCount)
    return NS_OK;

  *aCells = static_cast<PRInt32*>(
    nsMemory::Clone(selCells.Elements(), selCellsCount * sizeof(PRInt32)));
  NS_ENSURE_TRUE(*aCells, NS_ERROR_OUT_OF_MEMORY);

  *aCellsCount = selCellsCount;
  return NS_OK;
}
NS_IMETHODIMP
nsARIAGridAccessible::GetRowCount(PRInt32 *arowCount)
{
  NS_ENSURE_ARG_POINTER(arowCount);
  *arowCount = 0;

  if (IsDefunct())
    return NS_ERROR_FAILURE;

  AccIterator rowIter(this, filters::GetRow);
  while (rowIter.GetNext())
    (*arowCount)++;

  return NS_OK;
}
NS_IMETHODIMP
nsARIAGridAccessible::SelectRow(PRInt32 aRow)
{
  NS_ENSURE_ARG(IsValidRow(aRow));

  if (IsDefunct())
    return NS_ERROR_FAILURE;

  AccIterator rowIter(this, filters::GetRow);

  nsAccessible *row = nsnull;
  for (PRInt32 rowIdx = 0; (row = rowIter.GetNext()); rowIdx++) {
    nsresult rv = SetARIASelected(row, rowIdx == aRow);
    NS_ENSURE_SUCCESS(rv, rv);
  }

  return NS_OK;
}
NS_IMETHODIMP
nsARIAGridAccessible::GetColumnCount(PRInt32 *acolumnCount)
{
  NS_ENSURE_ARG_POINTER(acolumnCount);
  *acolumnCount = 0;

  if (IsDefunct())
    return NS_ERROR_FAILURE;

  AccIterator rowIter(this, filters::GetRow);
  nsAccessible *row = rowIter.GetNext();

  AccIterator cellIter(row, filters::GetCell);
  nsAccessible *cell = nsnull;

  while ((cell = cellIter.GetNext()))
    (*acolumnCount)++;

  return NS_OK;
}
NS_IMETHODIMP
nsARIAGridAccessible::UnselectColumn(PRInt32 aColumn)
{
  NS_ENSURE_ARG(IsValidColumn(aColumn));

  if (IsDefunct())
    return NS_ERROR_FAILURE;

  AccIterator rowIter(this, filters::GetRow);

  nsAccessible *row = nsnull;
  while ((row = rowIter.GetNext())) {
    nsAccessible *cell = GetCellInRowAt(row, aColumn);
    if (cell) {
      nsresult rv = SetARIASelected(cell, PR_FALSE);
      NS_ENSURE_SUCCESS(rv, rv);
    }
  }

  return NS_OK;
}
nsIFrame*
nsMathMLmtableOuterFrame::GetRowFrameAt(nsPresContext* aPresContext,
                                        PRInt32         aRowIndex)
{
  PRInt32 rowCount, colCount;
  GetTableSize(rowCount, colCount);

  // Negative indices mean to find upwards from the end.
  if (aRowIndex < 0) {
    aRowIndex = rowCount + aRowIndex;
  }
  // aRowIndex is 1-based, so convert it to a 0-based index
  --aRowIndex;

  // if our inner table says that the index is valid, find the row now
  if (0 <= aRowIndex && aRowIndex <= rowCount) {
    nsIFrame* tableFrame = mFrames.FirstChild();
    if (!tableFrame || tableFrame->GetType() != nsGkAtoms::tableFrame)
      return nsnull;
    nsIFrame* rgFrame = tableFrame->GetFirstChild(nsnull);
    if (!rgFrame || rgFrame->GetType() != nsGkAtoms::tableRowGroupFrame)
      return nsnull;
    nsTableIterator rowIter(*rgFrame);
    nsIFrame* rowFrame = rowIter.First();
    for ( ; rowFrame; rowFrame = rowIter.Next()) {
      if (aRowIndex == 0) {
        DEBUG_VERIFY_THAT_FRAME_IS(rowFrame, TABLE_ROW);
        if (rowFrame->GetType() != nsGkAtoms::tableRowFrame)
          return nsnull;

        return rowFrame;
      }
      --aRowIndex;
    }
  }
  return nsnull;
}
NS_IMETHODIMP
nsARIAGridAccessible::GetSelectedCells(nsIArray **aCells)
{
  NS_ENSURE_ARG_POINTER(aCells);
  *aCells = nsnull;

  if (IsDefunct())
    return NS_ERROR_FAILURE;

  nsresult rv = NS_OK;
  nsCOMPtr<nsIMutableArray> selCells =
    do_CreateInstance(NS_ARRAY_CONTRACTID, &rv);
  NS_ENSURE_SUCCESS(rv, rv);

  AccIterator rowIter(this, filters::GetRow);

  nsAccessible *row = nsnull;
  while ((row = rowIter.GetNext())) {
    AccIterator cellIter(row, filters::GetCell);
    nsAccessible *cell = nsnull;

    if (nsAccUtils::IsARIASelected(row)) {
      while ((cell = cellIter.GetNext()))
        selCells->AppendElement(static_cast<nsIAccessible *>(cell), PR_FALSE);

      continue;
    }

    while ((cell = cellIter.GetNext())) {
      if (nsAccUtils::IsARIASelected(cell))
        selCells->AppendElement(static_cast<nsIAccessible *>(cell), PR_FALSE);
    }
  }

  NS_ADDREF(*aCells = selCells);
  return NS_OK;
}
NS_IMETHODIMP
nsARIAGridAccessible::GetSelectedRowCount(PRUint32* aCount)
{
  NS_ENSURE_ARG_POINTER(aCount);
  *aCount = 0;

  if (IsDefunct())
    return NS_ERROR_FAILURE;

  AccIterator rowIter(this, filters::GetRow);

  nsAccessible *row = nsnull;
  while ((row = rowIter.GetNext())) {
    if (nsAccUtils::IsARIASelected(row)) {
      (*aCount)++;
      continue;
    }

    AccIterator cellIter(row, filters::GetCell);
    nsAccessible *cell = cellIter.GetNext();
    if (!cell)
      continue;

    PRBool isRowSelected = PR_TRUE;
    do {
      if (!nsAccUtils::IsARIASelected(cell)) {
        isRowSelected = PR_FALSE;
        break;
      }
    } while ((cell = cellIter.GetNext()));

    if (isRowSelected)
      (*aCount)++;
  }

  return NS_OK;
}
nsresult
nsARIAGridAccessible::GetSelectedColumnsArray(PRUint32 *acolumnCount,
                                              PRInt32 **aColumns)
{
  NS_ENSURE_ARG_POINTER(acolumnCount);
  *acolumnCount = 0;
  if (aColumns)
    *aColumns = nsnull;

  if (IsDefunct())
    return NS_ERROR_FAILURE;

  AccIterator rowIter(this, filters::GetRow);
  nsAccessible *row = rowIter.GetNext();
  if (!row)
    return NS_OK;

  PRInt32 colCount = 0;
  GetColumnCount(&colCount);
  if (!colCount)
    return NS_OK;

  PRInt32 selColCount = colCount;

  nsTArray<PRBool> isColSelArray(selColCount);
  isColSelArray.AppendElements(selColCount);
  for (PRInt32 i = 0; i < selColCount; i++)
    isColSelArray[i] = PR_TRUE;

  do {
    if (nsAccUtils::IsARIASelected(row))
      continue;

    PRInt32 colIdx = 0;

    AccIterator cellIter(row, filters::GetCell);
    nsAccessible *cell = nsnull;
    for (colIdx = 0; (cell = cellIter.GetNext()); colIdx++) {
      if (isColSelArray.SafeElementAt(colIdx, PR_FALSE) &&
          !nsAccUtils::IsARIASelected(cell)) {
        isColSelArray[colIdx] = PR_FALSE;
        selColCount--;
      }
    }
  } while ((row = rowIter.GetNext()));

  if (!selColCount)
    return NS_OK;

  if (!aColumns) {
    *acolumnCount = selColCount;
    return NS_OK;
  }

  *aColumns = static_cast<PRInt32*>(
    nsMemory::Alloc(selColCount * sizeof(PRInt32)));
  NS_ENSURE_TRUE(*aColumns, NS_ERROR_OUT_OF_MEMORY);

  *acolumnCount = selColCount;
  for (PRInt32 colIdx = 0, idx = 0; colIdx < colCount; colIdx++) {
    if (isColSelArray[colIdx])
      (*aColumns)[idx++] = colIdx;
  }

  return NS_OK;
}