void AccessibilityTableCell::rowIndexRange(pair<int, int>& rowRange) { if (!m_renderer || !m_renderer->isTableCell()) return; RenderTableCell* renderCell = toRenderTableCell(m_renderer); rowRange.first = renderCell->rowIndex(); rowRange.second = renderCell->rowSpan(); // since our table might have multiple sections, we have to offset our row appropriately RenderTableSection* section = renderCell->section(); RenderTable* table = renderCell->table(); if (!table || !section) return; // FIXME: This will skip a table with just a tfoot. Should fix by using RenderTable::topSection. RenderTableSection* tableSection = table->header(); if (!tableSection) tableSection = table->firstBody(); unsigned rowOffset = 0; while (tableSection) { if (tableSection == section) break; rowOffset += tableSection->numRows(); tableSection = table->sectionBelow(tableSection, SkipEmptySections); } rowRange.first += rowOffset; }
void AccessibilityTableCell::rowIndexRange(pair<int, int>& rowRange) { if (!m_renderer) return; RenderTableCell* renderCell = static_cast<RenderTableCell*>(m_renderer); rowRange.first = renderCell->row(); rowRange.second = renderCell->rowSpan(); // since our table might have multiple sections, we have to offset our row appropriately RenderTableSection* section = renderCell->section(); RenderTable* table = renderCell->table(); if (!table || !section) return; RenderTableSection* tableSection = table->header(); if (!tableSection) tableSection = table->firstBody(); unsigned rowOffset = 0; while (tableSection) { if (tableSection == section) break; rowOffset += tableSection->numRows(); tableSection = table->sectionBelow(tableSection, true); } rowRange.first += rowOffset; }
AccessibilityObject* AccessibilityTableColumn::headerObject() { if (!m_parent) return 0; RenderObject* renderer = m_parent->renderer(); if (!renderer) return 0; if (!m_parent->isAccessibilityTable()) return 0; AccessibilityTable* parentTable = toAccessibilityTable(m_parent); if (parentTable->isAriaTable()) { AccessibilityChildrenVector rowChildren = children(); unsigned childrenCount = rowChildren.size(); for (unsigned i = 0; i < childrenCount; ++i) { AccessibilityObject* cell = rowChildren[i].get(); if (cell->ariaRoleAttribute() == ColumnHeaderRole) return cell; } return 0; } if (!renderer->isTable()) return 0; RenderTable* table = toRenderTable(renderer); AccessibilityObject* headerObject = 0; // try the <thead> section first. this doesn't require th tags headerObject = headerObjectForSection(table->header(), false); if (headerObject) return headerObject; // now try for <th> tags in the first body headerObject = headerObjectForSection(table->firstBody(), true); return headerObject; }
AccessibilityTableCell* AccessibilityTable::cellForColumnAndRow(unsigned column, unsigned row) { if (!m_renderer) return 0; if (!hasChildren()) addChildren(); RenderTable* table = static_cast<RenderTable*>(m_renderer); RenderTableSection* tableSection = table->header(); if (!tableSection) tableSection = table->firstBody(); RenderTableCell* cell = 0; unsigned rowCount = 0; unsigned rowOffset = 0; while (tableSection) { rowCount += tableSection->numRows(); unsigned numCols = tableSection->numColumns(); if (row < rowCount && column < numCols) { int sectionSpecificRow = row - rowOffset; cell = tableSection->cellAt(sectionSpecificRow, column).cell; // we didn't find the cell, which means there's spanning happening // search backwards to find the spanning cell if (!cell) { // first try rows for (int testRow = sectionSpecificRow-1; testRow >= 0; --testRow) { cell = tableSection->cellAt(testRow, column).cell; // cell overlapped. use this one if (cell && ((cell->row() + (cell->rowSpan()-1)) >= (int)sectionSpecificRow)) break; cell = 0; } if (!cell) { // try cols for (int testCol = column-1; testCol >= 0; --testCol) { cell = tableSection->cellAt(sectionSpecificRow, testCol).cell; // cell overlapped. use this one if (cell && ((cell->col() + (cell->colSpan()-1)) >= (int)column)) break; cell = 0; } } } } if (cell) break; rowOffset += rowCount; // we didn't find anything between the rows we should have if (row < rowOffset) break; tableSection = table->sectionBelow(tableSection, true); } if (!cell) return 0; AccessibilityObject* cellObject = axObjectCache()->get(cell); ASSERT(cellObject->isTableCell()); return static_cast<AccessibilityTableCell*>(cellObject); }
void AccessibilityTable::addChildren() { if (!isDataTable()) { AccessibilityRenderObject::addChildren(); return; } ASSERT(!m_haveChildren); m_haveChildren = true; if (!m_renderer) return; RenderTable* table = static_cast<RenderTable*>(m_renderer); AXObjectCache* axCache = m_renderer->document()->axObjectCache(); // go through all the available sections to pull out the rows // and add them as children RenderTableSection* tableSection = table->header(); if (!tableSection) tableSection = table->firstBody(); if (!tableSection) return; RenderTableSection* initialTableSection = tableSection; while (tableSection) { HashSet<AccessibilityObject*> appendedRows; unsigned numRows = tableSection->numRows(); unsigned numCols = tableSection->numColumns(); for (unsigned rowIndex = 0; rowIndex < numRows; ++rowIndex) { for (unsigned colIndex = 0; colIndex < numCols; ++colIndex) { RenderTableCell* cell = tableSection->cellAt(rowIndex, colIndex).cell; if (!cell) continue; AccessibilityObject* rowObject = axCache->get(cell->parent()); if (!rowObject->isTableRow()) continue; AccessibilityTableRow* row = static_cast<AccessibilityTableRow*>(rowObject); // we need to check every cell for a new row, because cell spans // can cause us to mess rows if we just check the first column if (appendedRows.contains(row)) continue; row->setRowIndex((int)m_rows.size()); m_rows.append(row); m_children.append(row); appendedRows.add(row); } } tableSection = table->sectionBelow(tableSection, true); } // make the columns based on the number of columns in the first body unsigned length = initialTableSection->numColumns(); for (unsigned i = 0; i < length; ++i) { AccessibilityTableColumn* column = static_cast<AccessibilityTableColumn*>(axCache->get(ColumnRole)); column->setColumnIndex((int)i); column->setParentTable(this); m_columns.append(column); m_children.append(column); } AccessibilityObject* headerContainerObject = headerContainer(); if (headerContainerObject) m_children.append(headerContainerObject); }
AccessibilityTableCell* AccessibilityTable::cellForColumnAndRow(unsigned column, unsigned row) { if (!m_renderer || !m_renderer->isTable()) return 0; updateChildrenIfNecessary(); RenderTable* table = toRenderTable(m_renderer); // FIXME: This will skip a table with just a tfoot. Should fix by using RenderTable::topSection. RenderTableSection* tableSection = table->header(); if (!tableSection) tableSection = table->firstBody(); RenderTableCell* cell = 0; unsigned rowCount = 0; unsigned rowOffset = 0; while (tableSection) { unsigned numRows = tableSection->numRows(); unsigned numCols = tableSection->numColumns(); rowCount += numRows; unsigned sectionSpecificRow = row - rowOffset; if (row < rowCount && column < numCols && sectionSpecificRow < numRows) { cell = tableSection->primaryCellAt(sectionSpecificRow, column); // we didn't find the cell, which means there's spanning happening // search backwards to find the spanning cell if (!cell) { // first try rows for (int testRow = sectionSpecificRow - 1; testRow >= 0; --testRow) { cell = tableSection->primaryCellAt(testRow, column); // cell overlapped. use this one ASSERT(cell->rowSpan() >= 1); if (cell && ((cell->rowIndex() + (cell->rowSpan() - 1)) >= sectionSpecificRow)) break; cell = 0; } if (!cell) { // try cols for (int testCol = column - 1; testCol >= 0; --testCol) { cell = tableSection->primaryCellAt(sectionSpecificRow, testCol); // cell overlapped. use this one ASSERT(cell->rowSpan() >= 1); if (cell && ((cell->col() + (cell->colSpan() - 1)) >= column)) break; cell = 0; } } } } if (cell) break; rowOffset += numRows; // we didn't find anything between the rows we should have if (row < rowCount) break; tableSection = table->sectionBelow(tableSection, SkipEmptySections); } if (!cell) return 0; AccessibilityObject* cellObject = axObjectCache()->getOrCreate(cell); ASSERT(cellObject->isTableCell()); return static_cast<AccessibilityTableCell*>(cellObject); }
void AccessibilityTable::addChildren() { if (!isAccessibilityTable()) { AccessibilityRenderObject::addChildren(); return; } ASSERT(!m_haveChildren); m_haveChildren = true; if (!m_renderer || !m_renderer->isTable()) return; RenderTable* table = toRenderTable(m_renderer); AXObjectCache* axCache = m_renderer->document()->axObjectCache(); // go through all the available sections to pull out the rows // and add them as children // FIXME: This will skip a table with just a tfoot. Should fix by using RenderTable::topSection. RenderTableSection* tableSection = table->header(); if (!tableSection) tableSection = table->firstBody(); if (!tableSection) return; RenderTableSection* initialTableSection = tableSection; while (tableSection) { HashSet<AccessibilityObject*> appendedRows; unsigned numRows = tableSection->numRows(); unsigned numCols = tableSection->numColumns(); for (unsigned rowIndex = 0; rowIndex < numRows; ++rowIndex) { for (unsigned colIndex = 0; colIndex < numCols; ++colIndex) { RenderTableCell* cell = tableSection->primaryCellAt(rowIndex, colIndex); if (!cell) continue; AccessibilityObject* rowObject = axCache->getOrCreate(cell->parent()); if (!rowObject->isTableRow()) continue; AccessibilityTableRow* row = static_cast<AccessibilityTableRow*>(rowObject); // we need to check every cell for a new row, because cell spans // can cause us to mess rows if we just check the first column if (appendedRows.contains(row)) continue; row->setRowIndex((int)m_rows.size()); m_rows.append(row); if (!row->accessibilityIsIgnored()) m_children.append(row); #if PLATFORM(GTK) else m_children.append(row->children()); #endif appendedRows.add(row); } } tableSection = table->sectionBelow(tableSection, SkipEmptySections); } // make the columns based on the number of columns in the first body unsigned length = initialTableSection->numColumns(); for (unsigned i = 0; i < length; ++i) { AccessibilityTableColumn* column = static_cast<AccessibilityTableColumn*>(axCache->getOrCreate(ColumnRole)); column->setColumnIndex((int)i); column->setParent(this); m_columns.append(column); if (!column->accessibilityIsIgnored()) m_children.append(column); } AccessibilityObject* headerContainerObject = headerContainer(); if (headerContainerObject && !headerContainerObject->accessibilityIsIgnored()) m_children.append(headerContainerObject); }