michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* vim: set ts=2 et sw=2 tw=80: */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "InterfaceInitFuncs.h" michael@0: michael@0: #include "Accessible-inl.h" michael@0: #include "AccessibleWrap.h" michael@0: #include "nsAccUtils.h" michael@0: #include "TableAccessible.h" michael@0: #include "TableCellAccessible.h" michael@0: #include "nsMai.h" michael@0: michael@0: #include "nsArrayUtils.h" michael@0: michael@0: #include "mozilla/Likely.h" michael@0: michael@0: using namespace mozilla::a11y; michael@0: michael@0: extern "C" { michael@0: static AtkObject* michael@0: refAtCB(AtkTable* aTable, gint aRowIdx, gint aColIdx) michael@0: { michael@0: AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable)); michael@0: if (!accWrap || aRowIdx < 0 || aColIdx < 0) michael@0: return nullptr; michael@0: michael@0: Accessible* cell = accWrap->AsTable()->CellAt(aRowIdx, aColIdx); michael@0: if (!cell) michael@0: return nullptr; michael@0: michael@0: AtkObject* cellAtkObj = AccessibleWrap::GetAtkObject(cell); michael@0: if (cellAtkObj) michael@0: g_object_ref(cellAtkObj); michael@0: michael@0: return cellAtkObj; michael@0: } michael@0: michael@0: static gint michael@0: getIndexAtCB(AtkTable* aTable, gint aRowIdx, gint aColIdx) michael@0: { michael@0: AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable)); michael@0: if (!accWrap || aRowIdx < 0 || aColIdx < 0) michael@0: return -1; michael@0: michael@0: return static_cast(accWrap->AsTable()->CellIndexAt(aRowIdx, aColIdx)); michael@0: } michael@0: michael@0: static gint michael@0: getColumnAtIndexCB(AtkTable *aTable, gint aIdx) michael@0: { michael@0: AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable)); michael@0: if (!accWrap || aIdx < 0) michael@0: return -1; michael@0: michael@0: return static_cast(accWrap->AsTable()->ColIndexAt(aIdx)); michael@0: } michael@0: michael@0: static gint michael@0: getRowAtIndexCB(AtkTable *aTable, gint aIdx) michael@0: { michael@0: AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable)); michael@0: if (!accWrap || aIdx < 0) michael@0: return -1; michael@0: michael@0: return static_cast(accWrap->AsTable()->RowIndexAt(aIdx)); michael@0: } michael@0: michael@0: static gint michael@0: getColumnCountCB(AtkTable *aTable) michael@0: { michael@0: AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable)); michael@0: if (!accWrap) michael@0: return -1; michael@0: michael@0: return static_cast(accWrap->AsTable()->ColCount()); michael@0: } michael@0: michael@0: static gint michael@0: getRowCountCB(AtkTable *aTable) michael@0: { michael@0: AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable)); michael@0: if (!accWrap) michael@0: return -1; michael@0: michael@0: return static_cast(accWrap->AsTable()->RowCount()); michael@0: } michael@0: michael@0: static gint michael@0: getColumnExtentAtCB(AtkTable *aTable, gint aRowIdx, gint aColIdx) michael@0: { michael@0: AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable)); michael@0: if (!accWrap || aRowIdx < 0 || aColIdx < 0) michael@0: return -1; michael@0: michael@0: return static_cast(accWrap->AsTable()->ColExtentAt(aRowIdx, aColIdx)); michael@0: } michael@0: michael@0: static gint michael@0: getRowExtentAtCB(AtkTable *aTable, gint aRowIdx, gint aColIdx) michael@0: { michael@0: AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable)); michael@0: if (!accWrap) michael@0: return -1; michael@0: michael@0: return static_cast(accWrap->AsTable()->RowExtentAt(aRowIdx, aColIdx)); michael@0: } michael@0: michael@0: static AtkObject* michael@0: getCaptionCB(AtkTable* aTable) michael@0: { michael@0: AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable)); michael@0: if (!accWrap) michael@0: return nullptr; michael@0: michael@0: Accessible* caption = accWrap->AsTable()->Caption(); michael@0: return caption ? AccessibleWrap::GetAtkObject(caption) : nullptr; michael@0: } michael@0: michael@0: static const gchar* michael@0: getColumnDescriptionCB(AtkTable *aTable, gint aColumn) michael@0: { michael@0: AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable)); michael@0: if (!accWrap) michael@0: return nullptr; michael@0: michael@0: nsAutoString autoStr; michael@0: accWrap->AsTable()->ColDescription(aColumn, autoStr); michael@0: michael@0: return AccessibleWrap::ReturnString(autoStr); michael@0: } michael@0: michael@0: static AtkObject* michael@0: getColumnHeaderCB(AtkTable *aTable, gint aColIdx) michael@0: { michael@0: AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable)); michael@0: if (!accWrap) michael@0: return nullptr; michael@0: michael@0: Accessible* cell = accWrap->AsTable()->CellAt(0, aColIdx); michael@0: if (!cell) michael@0: return nullptr; michael@0: michael@0: // If the cell at the first row is column header then assume it is column michael@0: // header for all rows, michael@0: if (cell->Role() == roles::COLUMNHEADER) michael@0: return AccessibleWrap::GetAtkObject(cell); michael@0: michael@0: // otherwise get column header for the data cell at the first row. michael@0: TableCellAccessible* tableCell = cell->AsTableCell(); michael@0: if (!tableCell) michael@0: return nullptr; michael@0: michael@0: nsAutoTArray headerCells; michael@0: tableCell->ColHeaderCells(&headerCells); michael@0: if (headerCells.IsEmpty()) michael@0: return nullptr; michael@0: michael@0: return AccessibleWrap::GetAtkObject(headerCells[0]); michael@0: } michael@0: michael@0: static const gchar* michael@0: getRowDescriptionCB(AtkTable *aTable, gint aRow) michael@0: { michael@0: AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable)); michael@0: if (!accWrap) michael@0: return nullptr; michael@0: michael@0: nsAutoString autoStr; michael@0: accWrap->AsTable()->RowDescription(aRow, autoStr); michael@0: michael@0: return AccessibleWrap::ReturnString(autoStr); michael@0: } michael@0: michael@0: static AtkObject* michael@0: getRowHeaderCB(AtkTable *aTable, gint aRowIdx) michael@0: { michael@0: AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable)); michael@0: if (!accWrap) michael@0: return nullptr; michael@0: michael@0: Accessible* cell = accWrap->AsTable()->CellAt(aRowIdx, 0); michael@0: if (!cell) michael@0: return nullptr; michael@0: michael@0: // If the cell at the first column is row header then assume it is row michael@0: // header for all columns, michael@0: if (cell->Role() == roles::ROWHEADER) michael@0: return AccessibleWrap::GetAtkObject(cell); michael@0: michael@0: // otherwise get row header for the data cell at the first column. michael@0: TableCellAccessible* tableCell = cell->AsTableCell(); michael@0: if (!tableCell) michael@0: return nullptr; michael@0: michael@0: nsAutoTArray headerCells; michael@0: tableCell->RowHeaderCells(&headerCells); michael@0: if (headerCells.IsEmpty()) michael@0: return nullptr; michael@0: michael@0: return AccessibleWrap::GetAtkObject(headerCells[0]); michael@0: } michael@0: michael@0: static AtkObject* michael@0: getSummaryCB(AtkTable *aTable) michael@0: { michael@0: // Neither html:table nor xul:tree nor ARIA grid/tree have an ability to michael@0: // link an accessible object to specify a summary. There is closes method michael@0: // in TableAccessible::summary to get a summary as a string which is not michael@0: // mapped directly to ATK. michael@0: return nullptr; michael@0: } michael@0: michael@0: static gint michael@0: getSelectedColumnsCB(AtkTable *aTable, gint** aSelected) michael@0: { michael@0: *aSelected = nullptr; michael@0: michael@0: AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable)); michael@0: if (!accWrap) michael@0: return 0; michael@0: michael@0: nsAutoTArray cols; michael@0: accWrap->AsTable()->SelectedColIndices(&cols); michael@0: if (cols.IsEmpty()) michael@0: return 0; michael@0: michael@0: gint* atkColumns = g_new(gint, cols.Length()); michael@0: if (!atkColumns) { michael@0: NS_WARNING("OUT OF MEMORY"); michael@0: return 0; michael@0: } michael@0: michael@0: memcpy(atkColumns, cols.Elements(), cols.Length() * sizeof(uint32_t)); michael@0: *aSelected = atkColumns; michael@0: return cols.Length(); michael@0: } michael@0: michael@0: static gint michael@0: getSelectedRowsCB(AtkTable *aTable, gint **aSelected) michael@0: { michael@0: AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable)); michael@0: if (!accWrap) michael@0: return 0; michael@0: michael@0: nsAutoTArray rows; michael@0: accWrap->AsTable()->SelectedRowIndices(&rows); michael@0: michael@0: gint* atkRows = g_new(gint, rows.Length()); michael@0: if (!atkRows) { michael@0: NS_WARNING("OUT OF MEMORY"); michael@0: return 0; michael@0: } michael@0: michael@0: memcpy(atkRows, rows.Elements(), rows.Length() * sizeof(uint32_t)); michael@0: *aSelected = atkRows; michael@0: return rows.Length(); michael@0: } michael@0: michael@0: static gboolean michael@0: isColumnSelectedCB(AtkTable *aTable, gint aColIdx) michael@0: { michael@0: AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable)); michael@0: if (!accWrap) michael@0: return FALSE; michael@0: michael@0: return static_cast(accWrap->AsTable()->IsColSelected(aColIdx)); michael@0: } michael@0: michael@0: static gboolean michael@0: isRowSelectedCB(AtkTable *aTable, gint aRowIdx) michael@0: { michael@0: AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable)); michael@0: if (!accWrap) michael@0: return FALSE; michael@0: michael@0: return static_cast(accWrap->AsTable()->IsRowSelected(aRowIdx)); michael@0: } michael@0: michael@0: static gboolean michael@0: isCellSelectedCB(AtkTable *aTable, gint aRowIdx, gint aColIdx) michael@0: { michael@0: AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable)); michael@0: if (!accWrap) michael@0: return FALSE; michael@0: michael@0: return static_cast(accWrap->AsTable()-> michael@0: IsCellSelected(aRowIdx, aColIdx)); michael@0: } michael@0: } michael@0: michael@0: void michael@0: tableInterfaceInitCB(AtkTableIface* aIface) michael@0: { michael@0: NS_ASSERTION(aIface, "no interface!"); michael@0: if (MOZ_UNLIKELY(!aIface)) michael@0: return; michael@0: michael@0: aIface->ref_at = refAtCB; michael@0: aIface->get_index_at = getIndexAtCB; michael@0: aIface->get_column_at_index = getColumnAtIndexCB; michael@0: aIface->get_row_at_index = getRowAtIndexCB; michael@0: aIface->get_n_columns = getColumnCountCB; michael@0: aIface->get_n_rows = getRowCountCB; michael@0: aIface->get_column_extent_at = getColumnExtentAtCB; michael@0: aIface->get_row_extent_at = getRowExtentAtCB; michael@0: aIface->get_caption = getCaptionCB; michael@0: aIface->get_column_description = getColumnDescriptionCB; michael@0: aIface->get_column_header = getColumnHeaderCB; michael@0: aIface->get_row_description = getRowDescriptionCB; michael@0: aIface->get_row_header = getRowHeaderCB; michael@0: aIface->get_summary = getSummaryCB; michael@0: aIface->get_selected_columns = getSelectedColumnsCB; michael@0: aIface->get_selected_rows = getSelectedRowsCB; michael@0: aIface->is_column_selected = isColumnSelectedCB; michael@0: aIface->is_row_selected = isRowSelectedCB; michael@0: aIface->is_selected = isCellSelectedCB; michael@0: }