1/* 2 * Copyright (C) 2008 Nuanti Ltd. 3 * Copyright (C) 2009 Jan Alonzo 4 * Copyright (C) 2009, 2010, 2011, 2012 Igalia S.L. 5 * 6 * Portions from Mozilla a11y, copyright as follows: 7 * 8 * The Original Code is mozilla.org code. 9 * 10 * The Initial Developer of the Original Code is 11 * Sun Microsystems, Inc. 12 * Portions created by the Initial Developer are Copyright (C) 2002 13 * the Initial Developer. All Rights Reserved. 14 * 15 * This library is free software; you can redistribute it and/or 16 * modify it under the terms of the GNU Library General Public 17 * License as published by the Free Software Foundation; either 18 * version 2 of the License, or (at your option) any later version. 19 * 20 * This library is distributed in the hope that it will be useful, 21 * but WITHOUT ANY WARRANTY; without even the implied warranty of 22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 23 * Library General Public License for more details. 24 * 25 * You should have received a copy of the GNU Library General Public License 26 * along with this library; see the file COPYING.LIB. If not, write to 27 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 28 * Boston, MA 02110-1301, USA. 29 */ 30 31#include "config.h" 32#include "WebKitAccessibleInterfaceTable.h" 33 34#if HAVE(ACCESSIBILITY) 35 36#include "AccessibilityListBox.h" 37#include "AccessibilityObject.h" 38#include "AccessibilityTable.h" 39#include "AccessibilityTableCell.h" 40#include "HTMLSelectElement.h" 41#include "HTMLTableCaptionElement.h" 42#include "HTMLTableElement.h" 43#include "RenderObject.h" 44#include "WebKitAccessibleInterfaceText.h" 45#include "WebKitAccessibleWrapperAtk.h" 46 47using namespace WebCore; 48 49static AccessibilityObject* core(AtkTable* table) 50{ 51 if (!WEBKIT_IS_ACCESSIBLE(table)) 52 return 0; 53 54 return webkitAccessibleGetAccessibilityObject(WEBKIT_ACCESSIBLE(table)); 55} 56 57static AccessibilityTableCell* cell(AtkTable* table, guint row, guint column) 58{ 59 AccessibilityObject* accTable = core(table); 60 if (accTable->isAccessibilityRenderObject()) 61 return static_cast<AccessibilityTable*>(accTable)->cellForColumnAndRow(column, row); 62 return 0; 63} 64 65static gint cellIndex(AccessibilityTableCell* axCell, AccessibilityTable* axTable) 66{ 67 // Calculate the cell's index as if we had a traditional Gtk+ table in 68 // which cells are all direct children of the table, arranged row-first. 69 AccessibilityObject::AccessibilityChildrenVector allCells; 70 axTable->cells(allCells); 71 AccessibilityObject::AccessibilityChildrenVector::iterator position; 72 position = std::find(allCells.begin(), allCells.end(), axCell); 73 if (position == allCells.end()) 74 return -1; 75 return position - allCells.begin(); 76} 77 78static AccessibilityTableCell* cellAtIndex(AtkTable* table, gint index) 79{ 80 AccessibilityObject* accTable = core(table); 81 if (accTable->isAccessibilityRenderObject()) { 82 AccessibilityObject::AccessibilityChildrenVector allCells; 83 static_cast<AccessibilityTable*>(accTable)->cells(allCells); 84 if (0 <= index && static_cast<unsigned>(index) < allCells.size()) { 85 AccessibilityObject* accCell = allCells.at(index).get(); 86 return static_cast<AccessibilityTableCell*>(accCell); 87 } 88 } 89 return 0; 90} 91 92static AtkObject* webkitAccessibleTableRefAt(AtkTable* table, gint row, gint column) 93{ 94 AccessibilityTableCell* axCell = cell(table, row, column); 95 if (!axCell) 96 return 0; 97 98 AtkObject* cell = axCell->wrapper(); 99 if (!cell) 100 return 0; 101 102 // This method transfers full ownership over the returned 103 // AtkObject, so an extra reference is needed here. 104 return ATK_OBJECT(g_object_ref(cell)); 105} 106 107static gint webkitAccessibleTableGetIndexAt(AtkTable* table, gint row, gint column) 108{ 109 AccessibilityTableCell* axCell = cell(table, row, column); 110 AccessibilityTable* axTable = static_cast<AccessibilityTable*>(core(table)); 111 return cellIndex(axCell, axTable); 112} 113 114static gint webkitAccessibleTableGetColumnAtIndex(AtkTable* table, gint index) 115{ 116 AccessibilityTableCell* axCell = cellAtIndex(table, index); 117 if (axCell) { 118 pair<unsigned, unsigned> columnRange; 119 axCell->columnIndexRange(columnRange); 120 return columnRange.first; 121 } 122 return -1; 123} 124 125static gint webkitAccessibleTableGetRowAtIndex(AtkTable* table, gint index) 126{ 127 AccessibilityTableCell* axCell = cellAtIndex(table, index); 128 if (axCell) { 129 pair<unsigned, unsigned> rowRange; 130 axCell->rowIndexRange(rowRange); 131 return rowRange.first; 132 } 133 return -1; 134} 135 136static gint webkitAccessibleTableGetNColumns(AtkTable* table) 137{ 138 AccessibilityObject* accTable = core(table); 139 if (accTable->isAccessibilityRenderObject()) 140 return static_cast<AccessibilityTable*>(accTable)->columnCount(); 141 return 0; 142} 143 144static gint webkitAccessibleTableGetNRows(AtkTable* table) 145{ 146 AccessibilityObject* accTable = core(table); 147 if (accTable->isAccessibilityRenderObject()) 148 return static_cast<AccessibilityTable*>(accTable)->rowCount(); 149 return 0; 150} 151 152static gint webkitAccessibleTableGetColumnExtentAt(AtkTable* table, gint row, gint column) 153{ 154 AccessibilityTableCell* axCell = cell(table, row, column); 155 if (axCell) { 156 pair<unsigned, unsigned> columnRange; 157 axCell->columnIndexRange(columnRange); 158 return columnRange.second; 159 } 160 return 0; 161} 162 163static gint webkitAccessibleTableGetRowExtentAt(AtkTable* table, gint row, gint column) 164{ 165 AccessibilityTableCell* axCell = cell(table, row, column); 166 if (axCell) { 167 pair<unsigned, unsigned> rowRange; 168 axCell->rowIndexRange(rowRange); 169 return rowRange.second; 170 } 171 return 0; 172} 173 174static AtkObject* webkitAccessibleTableGetColumnHeader(AtkTable* table, gint column) 175{ 176 AccessibilityObject* accTable = core(table); 177 if (accTable->isAccessibilityRenderObject()) { 178 AccessibilityObject::AccessibilityChildrenVector allColumnHeaders; 179 static_cast<AccessibilityTable*>(accTable)->columnHeaders(allColumnHeaders); 180 unsigned columnCount = allColumnHeaders.size(); 181 for (unsigned k = 0; k < columnCount; ++k) { 182 pair<unsigned, unsigned> columnRange; 183 AccessibilityTableCell* cell = static_cast<AccessibilityTableCell*>(allColumnHeaders.at(k).get()); 184 cell->columnIndexRange(columnRange); 185 if (columnRange.first <= static_cast<unsigned>(column) && static_cast<unsigned>(column) < columnRange.first + columnRange.second) 186 return allColumnHeaders[k]->wrapper(); 187 } 188 } 189 return 0; 190} 191 192static AtkObject* webkitAccessibleTableGetRowHeader(AtkTable* table, gint row) 193{ 194 AccessibilityObject* accTable = core(table); 195 if (accTable->isAccessibilityRenderObject()) { 196 AccessibilityObject::AccessibilityChildrenVector allRowHeaders; 197 static_cast<AccessibilityTable*>(accTable)->rowHeaders(allRowHeaders); 198 unsigned rowCount = allRowHeaders.size(); 199 for (unsigned k = 0; k < rowCount; ++k) { 200 pair<unsigned, unsigned> rowRange; 201 AccessibilityTableCell* cell = static_cast<AccessibilityTableCell*>(allRowHeaders.at(k).get()); 202 cell->rowIndexRange(rowRange); 203 if (rowRange.first <= static_cast<unsigned>(row) && static_cast<unsigned>(row) < rowRange.first + rowRange.second) 204 return allRowHeaders[k]->wrapper(); 205 } 206 } 207 return 0; 208} 209 210static AtkObject* webkitAccessibleTableGetCaption(AtkTable* table) 211{ 212 AccessibilityObject* accTable = core(table); 213 if (accTable->isAccessibilityRenderObject()) { 214 Node* node = accTable->node(); 215 if (node && node->hasTagName(HTMLNames::tableTag)) { 216 HTMLTableCaptionElement* caption = static_cast<HTMLTableElement*>(node)->caption(); 217 if (caption) 218 return AccessibilityObject::firstAccessibleObjectFromNode(caption->renderer()->node())->wrapper(); 219 } 220 } 221 return 0; 222} 223 224static const gchar* webkitAccessibleTableGetColumnDescription(AtkTable* table, gint column) 225{ 226 AtkObject* columnHeader = atk_table_get_column_header(table, column); 227 if (columnHeader && ATK_IS_TEXT(columnHeader)) 228 return atk_text_get_text(ATK_TEXT(columnHeader), 0, -1); 229 230 return 0; 231} 232 233static const gchar* webkitAccessibleTableGetRowDescription(AtkTable* table, gint row) 234{ 235 AtkObject* rowHeader = atk_table_get_row_header(table, row); 236 if (rowHeader && ATK_IS_TEXT(rowHeader)) 237 return atk_text_get_text(ATK_TEXT(rowHeader), 0, -1); 238 239 return 0; 240} 241 242void webkitAccessibleTableInterfaceInit(AtkTableIface* iface) 243{ 244 iface->ref_at = webkitAccessibleTableRefAt; 245 iface->get_index_at = webkitAccessibleTableGetIndexAt; 246 iface->get_column_at_index = webkitAccessibleTableGetColumnAtIndex; 247 iface->get_row_at_index = webkitAccessibleTableGetRowAtIndex; 248 iface->get_n_columns = webkitAccessibleTableGetNColumns; 249 iface->get_n_rows = webkitAccessibleTableGetNRows; 250 iface->get_column_extent_at = webkitAccessibleTableGetColumnExtentAt; 251 iface->get_row_extent_at = webkitAccessibleTableGetRowExtentAt; 252 iface->get_column_header = webkitAccessibleTableGetColumnHeader; 253 iface->get_row_header = webkitAccessibleTableGetRowHeader; 254 iface->get_caption = webkitAccessibleTableGetCaption; 255 iface->get_column_description = webkitAccessibleTableGetColumnDescription; 256 iface->get_row_description = webkitAccessibleTableGetRowDescription; 257} 258 259#endif 260