nsresult
XULTreeGridCellAccessible::GetAttributesInternal(nsIPersistentProperties* aAttributes)
{
  NS_ENSURE_ARG_POINTER(aAttributes);

  if (IsDefunct())
    return NS_ERROR_FAILURE;

  // "table-cell-index" attribute
  TableAccessible* table = Table();
  if (!table)
    return NS_ERROR_FAILURE;

  nsAutoString stringIdx;
  stringIdx.AppendInt(table->CellIndexAt(mRow, ColIdx()));
  nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::tableCellIndex, stringIdx);

  // "cycles" attribute
  bool isCycler = false;
  nsresult rv = mColumn->GetCycler(&isCycler);
  if (NS_SUCCEEDED(rv) && isCycler)
    nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::cycles,
                           NS_LITERAL_STRING("true"));

  return NS_OK;
}
void
XULListCellAccessible::ColHeaderCells(nsTArray<Accessible*>* aCells)
{
  TableAccessible* table = Table();
  NS_ASSERTION(table, "cell not in a table!");
  if (!table)
    return;

  // Get column header cell from XUL listhead.
  Accessible* list = nullptr;

  Accessible* tableAcc = table->AsAccessible();
  uint32_t tableChildCount = tableAcc->ChildCount();
  for (uint32_t childIdx = 0; childIdx < tableChildCount; childIdx++) {
    Accessible* child = tableAcc->GetChildAt(childIdx);
    if (child->Role() == roles::LIST) {
      list = child;
      break;
    }
  }

  if (list) {
    Accessible* headerCell = list->GetChildAt(ColIdx());
    if (headerCell) {
      aCells->AppendElement(headerCell);
      return;
    }
  }

  // No column header cell from XUL markup, try to get it from ARIA markup.
  TableCellAccessible::ColHeaderCells(aCells);
}
bool
XULListCellAccessible::Selected()
{
  TableAccessible* table = Table();
  NS_ENSURE_TRUE(table, false); // we expect to be in a listbox (table)

  return table->IsRowSelected(RowIdx());
}
already_AddRefed<nsIPersistentProperties>
HTMLTableCellAccessible::NativeAttributes()
{
  nsCOMPtr<nsIPersistentProperties> attributes =
    HyperTextAccessibleWrap::NativeAttributes();

  // table-cell-index attribute
  TableAccessible* table = Table();
  if (!table)
    return attributes.forget();

  int32_t rowIdx = -1, colIdx = -1;
  nsresult rv = GetCellIndexes(rowIdx, colIdx);
  if (NS_FAILED(rv))
    return attributes.forget();

  nsAutoString stringIdx;
  stringIdx.AppendInt(table->CellIndexAt(rowIdx, colIdx));
  nsAccUtils::SetAccAttr(attributes, nsGkAtoms::tableCellIndex, stringIdx);

  // abbr attribute

  // Pick up object attribute from abbr DOM element (a child of the cell) or
  // from abbr DOM attribute.
  nsAutoString abbrText;
  if (ChildCount() == 1) {
    Accessible* abbr = FirstChild();
    if (abbr->IsAbbreviation()) {
      nsIContent* firstChildNode = abbr->GetContent()->GetFirstChild();
      if (firstChildNode) {
        nsTextEquivUtils::
          AppendTextEquivFromTextContent(firstChildNode, &abbrText);
      }
    }
  }
  if (abbrText.IsEmpty())
    mContent->AsElement()->GetAttr(kNameSpaceID_None, nsGkAtoms::abbr, abbrText);

  if (!abbrText.IsEmpty())
    nsAccUtils::SetAccAttr(attributes, nsGkAtoms::abbr, abbrText);

  // axis attribute
  nsAutoString axisText;
  mContent->AsElement()->GetAttr(kNameSpaceID_None, nsGkAtoms::axis, axisText);
  if (!axisText.IsEmpty())
    nsAccUtils::SetAccAttr(attributes, nsGkAtoms::axis, axisText);

#ifdef DEBUG
  nsAutoString unused;
  attributes->SetStringProperty(NS_LITERAL_CSTRING("cppclass"),
                                NS_LITERAL_STRING("HTMLTableCellAccessible"),
                                unused);
#endif

  return attributes.forget();
}
bool
HTMLTableCellAccessible::Selected()
{
  int32_t rowIdx = -1, colIdx = -1;
  GetCellIndexes(rowIdx, colIdx);

  TableAccessible* table = Table();
  NS_ENSURE_TRUE(table, false);

  return table->IsCellSelected(rowIdx, colIdx);
}
GroupPos ARIAGridCellAccessible::GroupPosition() {
  int32_t count = 0, index = 0;
  TableAccessible* table = Table();
  if (table &&
      nsCoreUtils::GetUIntAttr(table->AsAccessible()->GetContent(),
                               nsGkAtoms::aria_colcount, &count) &&
      nsCoreUtils::GetUIntAttr(mContent, nsGkAtoms::aria_colindex, &index)) {
    return GroupPos(0, index, count);
  }

  return GroupPos();
}
static gint
getIndexAtCB(AtkTable* aTable, gint aRow, gint aColumn)
{
  AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
  if (!accWrap)
    return -1;

  TableAccessible* table = accWrap->AsTable();
  NS_ENSURE_TRUE(table, -1);

  return static_cast<gint>(table->CellIndexAt(aRow, aColumn));
}
uint32_t
HTMLTableCellAccessible::RowExtent() const
{
  int32_t rowIdx = -1, colIdx = -1;
  GetCellIndexes(rowIdx, colIdx);

  TableAccessible* table = Table();
  NS_ASSERTION(table, "cell not in atable!");
  if (!table)
    return 0;

  return table->RowExtentAt(rowIdx, colIdx);
}
static AtkObject*
getCaptionCB(AtkTable* aTable)
{
  AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
  if (!accWrap)
    return nsnull;

  TableAccessible* table = accWrap->AsTable();
  NS_ENSURE_TRUE(table, nsnull);

  Accessible* caption = table->Caption();
  return caption ? AccessibleWrap::GetAtkObject(caption) : nsnull;
}
already_AddRefed<nsIPersistentProperties>
XULListCellAccessible::NativeAttributes()
{
  nsCOMPtr<nsIPersistentProperties> attributes =
    HyperTextAccessibleWrap::NativeAttributes();

  // "table-cell-index" attribute
  TableAccessible* table = Table();
  if (!table) // we expect to be in a listbox (table)
    return attributes.forget();

  nsAutoString stringIdx;
  stringIdx.AppendInt(table->CellIndexAt(RowIdx(), ColIdx()));
  nsAccUtils::SetAccAttr(attributes, nsGkAtoms::tableCellIndex, stringIdx);

  return attributes.forget();
}
NS_IMETHODIMP
xpcAccessibleTableCell::GetTable(nsIAccessibleTable** aTable)
{
  NS_ENSURE_ARG_POINTER(aTable);
  *aTable = nullptr;

  if (!Intl())
    return NS_ERROR_FAILURE;

  TableAccessible* table = Intl()->Table();
  if (!table)
    return NS_ERROR_FAILURE;

  nsCOMPtr<nsIAccessibleTable> xpcTable =
    do_QueryInterface(static_cast<nsIAccessible*>(ToXPC(table->AsAccessible())));
  xpcTable.forget(aTable);
  return NS_OK;
}
already_AddRefed<nsIPersistentProperties>
XULTreeGridCellAccessible::NativeAttributes() {
  RefPtr<nsPersistentProperties> attributes = new nsPersistentProperties();

  // "table-cell-index" attribute
  TableAccessible* table = Table();
  if (!table) return attributes.forget();

  nsAutoString stringIdx;
  stringIdx.AppendInt(table->CellIndexAt(mRow, ColIdx()));
  nsAccUtils::SetAccAttr(attributes, nsGkAtoms::tableCellIndex, stringIdx);

  // "cycles" attribute
  if (mColumn->Cycler())
    nsAccUtils::SetAccAttr(attributes, nsGkAtoms::cycles,
                           NS_LITERAL_STRING("true"));

  return attributes.forget();
}
role
HTMLTableHeaderCellAccessible::NativeRole()
{
  // Check value of @scope attribute.
  static Element::AttrValuesArray scopeValues[] =
    { &nsGkAtoms::col, &nsGkAtoms::colgroup,
      &nsGkAtoms::row, &nsGkAtoms::rowgroup, nullptr };
  int32_t valueIdx =
    mContent->AsElement()->FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::scope,
                                           scopeValues, eCaseMatters);

  switch (valueIdx) {
    case 0:
    case 1:
      return roles::COLUMNHEADER;
    case 2:
    case 3:
      return roles::ROWHEADER;
  }

  TableAccessible* table = Table();
  if (!table)
    return roles::NOTHING;

  // If the cell next to this one is not a header cell then assume this cell is
  // a row header for it.
  uint32_t rowIdx = RowIdx(), colIdx = ColIdx();
  Accessible* cell = table->CellAt(rowIdx, colIdx + ColExtent());
  if (cell && !nsCoreUtils::IsHTMLTableHeader(cell->GetContent()))
    return roles::ROWHEADER;

  // If the cell below this one is not a header cell then assume this cell is
  // a column header for it.
  uint32_t rowExtent = RowExtent();
  cell = table->CellAt(rowIdx + rowExtent, colIdx);
  if (cell && !nsCoreUtils::IsHTMLTableHeader(cell->GetContent()))
    return roles::COLUMNHEADER;

  // Otherwise if this cell is surrounded by header cells only then make a guess
  // based on its cell spanning. In other words if it is row spanned then assume
  // it's a row header, otherwise it's a column header.
  return rowExtent > 1 ? roles::ROWHEADER : roles::COLUMNHEADER;
}
already_AddRefed<nsIPersistentProperties>
XULTreeGridCellAccessible::NativeAttributes()
{
  nsCOMPtr<nsIPersistentProperties> attributes =
    do_CreateInstance(NS_PERSISTENTPROPERTIES_CONTRACTID);

  // "table-cell-index" attribute
  TableAccessible* table = Table();
  if (!table)
    return attributes.forget();

  nsAutoString stringIdx;
  stringIdx.AppendInt(table->CellIndexAt(mRow, ColIdx()));
  nsAccUtils::SetAccAttr(attributes, nsGkAtoms::tableCellIndex, stringIdx);

  // "cycles" attribute
  bool isCycler = false;
  nsresult rv = mColumn->GetCycler(&isCycler);
  if (NS_SUCCEEDED(rv) && isCycler)
    nsAccUtils::SetAccAttr(attributes, nsGkAtoms::cycles,
                           NS_LITERAL_STRING("true"));

  return attributes.forget();
}