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 "RenderElement.h" 44#include "WebKitAccessibleInterfaceText.h" 45#include "WebKitAccessibleUtil.h" 46#include "WebKitAccessibleWrapperAtk.h" 47 48using namespace WebCore; 49 50static AccessibilityObject* core(AtkTable* table) 51{ 52 if (!WEBKIT_IS_ACCESSIBLE(table)) 53 return 0; 54 55 return webkitAccessibleGetAccessibilityObject(WEBKIT_ACCESSIBLE(table)); 56} 57 58static AccessibilityTableCell* cell(AtkTable* table, guint row, guint column) 59{ 60 AccessibilityObject* accTable = core(table); 61 if (accTable->isAccessibilityRenderObject()) 62 return toAccessibilityTable(accTable)->cellForColumnAndRow(column, row); 63 return 0; 64} 65 66static gint cellIndex(AccessibilityTableCell* axCell, AccessibilityTable* axTable) 67{ 68 // Calculate the cell's index as if we had a traditional Gtk+ table in 69 // which cells are all direct children of the table, arranged row-first. 70 AccessibilityObject::AccessibilityChildrenVector allCells; 71 axTable->cells(allCells); 72 AccessibilityObject::AccessibilityChildrenVector::iterator position; 73 position = std::find(allCells.begin(), allCells.end(), axCell); 74 if (position == allCells.end()) 75 return -1; 76 return position - allCells.begin(); 77} 78 79static AccessibilityTableCell* cellAtIndex(AtkTable* table, gint index) 80{ 81 AccessibilityObject* accTable = core(table); 82 if (accTable->isAccessibilityRenderObject()) { 83 AccessibilityObject::AccessibilityChildrenVector allCells; 84 toAccessibilityTable(accTable)->cells(allCells); 85 if (0 <= index && static_cast<unsigned>(index) < allCells.size()) { 86 AccessibilityObject* accCell = allCells.at(index).get(); 87 return toAccessibilityTableCell(accCell); 88 } 89 } 90 return 0; 91} 92 93static AtkObject* webkitAccessibleTableRefAt(AtkTable* table, gint row, gint column) 94{ 95 g_return_val_if_fail(ATK_TABLE(table), 0); 96 returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(table), 0); 97 98 AccessibilityTableCell* axCell = cell(table, row, column); 99 if (!axCell) 100 return 0; 101 102 AtkObject* cell = axCell->wrapper(); 103 if (!cell) 104 return 0; 105 106 // This method transfers full ownership over the returned 107 // AtkObject, so an extra reference is needed here. 108 return ATK_OBJECT(g_object_ref(cell)); 109} 110 111static gint webkitAccessibleTableGetIndexAt(AtkTable* table, gint row, gint column) 112{ 113 g_return_val_if_fail(ATK_TABLE(table), -1); 114 returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(table), -1); 115 116 AccessibilityTableCell* axCell = cell(table, row, column); 117 AccessibilityTable* axTable = toAccessibilityTable(core(table)); 118 return cellIndex(axCell, axTable); 119} 120 121static gint webkitAccessibleTableGetColumnAtIndex(AtkTable* table, gint index) 122{ 123 g_return_val_if_fail(ATK_TABLE(table), -1); 124 returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(table), -1); 125 126 AccessibilityTableCell* axCell = cellAtIndex(table, index); 127 if (axCell) { 128 std::pair<unsigned, unsigned> columnRange; 129 axCell->columnIndexRange(columnRange); 130 return columnRange.first; 131 } 132 return -1; 133} 134 135static gint webkitAccessibleTableGetRowAtIndex(AtkTable* table, gint index) 136{ 137 g_return_val_if_fail(ATK_TABLE(table), -1); 138 returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(table), -1); 139 140 AccessibilityTableCell* axCell = cellAtIndex(table, index); 141 if (axCell) { 142 std::pair<unsigned, unsigned> rowRange; 143 axCell->rowIndexRange(rowRange); 144 return rowRange.first; 145 } 146 return -1; 147} 148 149static gint webkitAccessibleTableGetNColumns(AtkTable* table) 150{ 151 g_return_val_if_fail(ATK_TABLE(table), 0); 152 returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(table), 0); 153 154 AccessibilityObject* accTable = core(table); 155 if (accTable->isAccessibilityRenderObject()) 156 return toAccessibilityTable(accTable)->columnCount(); 157 return 0; 158} 159 160static gint webkitAccessibleTableGetNRows(AtkTable* table) 161{ 162 g_return_val_if_fail(ATK_TABLE(table), 0); 163 returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(table), 0); 164 165 AccessibilityObject* accTable = core(table); 166 if (accTable->isAccessibilityRenderObject()) 167 return toAccessibilityTable(accTable)->rowCount(); 168 return 0; 169} 170 171static gint webkitAccessibleTableGetColumnExtentAt(AtkTable* table, gint row, gint column) 172{ 173 g_return_val_if_fail(ATK_TABLE(table), 0); 174 returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(table), 0); 175 176 AccessibilityTableCell* axCell = cell(table, row, column); 177 if (axCell) { 178 std::pair<unsigned, unsigned> columnRange; 179 axCell->columnIndexRange(columnRange); 180 return columnRange.second; 181 } 182 return 0; 183} 184 185static gint webkitAccessibleTableGetRowExtentAt(AtkTable* table, gint row, gint column) 186{ 187 g_return_val_if_fail(ATK_TABLE(table), 0); 188 returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(table), 0); 189 190 AccessibilityTableCell* axCell = cell(table, row, column); 191 if (axCell) { 192 std::pair<unsigned, unsigned> rowRange; 193 axCell->rowIndexRange(rowRange); 194 return rowRange.second; 195 } 196 return 0; 197} 198 199static AtkObject* webkitAccessibleTableGetColumnHeader(AtkTable* table, gint column) 200{ 201 g_return_val_if_fail(ATK_TABLE(table), 0); 202 returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(table), 0); 203 204 AccessibilityObject* accTable = core(table); 205 if (accTable->isAccessibilityRenderObject()) { 206 AccessibilityObject::AccessibilityChildrenVector columnHeaders; 207 toAccessibilityTable(accTable)->columnHeaders(columnHeaders); 208 209 for (const auto& columnHeader : columnHeaders) { 210 std::pair<unsigned, unsigned> columnRange; 211 toAccessibilityTableCell(columnHeader.get())->columnIndexRange(columnRange); 212 if (columnRange.first <= static_cast<unsigned>(column) && static_cast<unsigned>(column) < columnRange.first + columnRange.second) 213 return columnHeader->wrapper(); 214 } 215 } 216 return 0; 217} 218 219static AtkObject* webkitAccessibleTableGetRowHeader(AtkTable* table, gint row) 220{ 221 g_return_val_if_fail(ATK_TABLE(table), 0); 222 returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(table), 0); 223 224 AccessibilityObject* accTable = core(table); 225 if (accTable->isAccessibilityRenderObject()) { 226 AccessibilityObject::AccessibilityChildrenVector rowHeaders; 227 toAccessibilityTable(accTable)->rowHeaders(rowHeaders); 228 229 for (const auto& rowHeader : rowHeaders) { 230 std::pair<unsigned, unsigned> rowRange; 231 toAccessibilityTableCell(rowHeader.get())->rowIndexRange(rowRange); 232 if (rowRange.first <= static_cast<unsigned>(row) && static_cast<unsigned>(row) < rowRange.first + rowRange.second) 233 return rowHeader->wrapper(); 234 } 235 } 236 return 0; 237} 238 239static AtkObject* webkitAccessibleTableGetCaption(AtkTable* table) 240{ 241 g_return_val_if_fail(ATK_TABLE(table), 0); 242 returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(table), 0); 243 244 AccessibilityObject* accTable = core(table); 245 if (accTable->isAccessibilityRenderObject()) { 246 Node* node = accTable->node(); 247 if (node && isHTMLTableElement(node)) { 248 HTMLTableCaptionElement* caption = toHTMLTableElement(node)->caption(); 249 if (caption) 250 return AccessibilityObject::firstAccessibleObjectFromNode(caption->renderer()->element())->wrapper(); 251 } 252 } 253 return 0; 254} 255 256static const gchar* webkitAccessibleTableGetColumnDescription(AtkTable* table, gint column) 257{ 258 g_return_val_if_fail(ATK_TABLE(table), 0); 259 returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(table), 0); 260 261 AtkObject* columnHeader = atk_table_get_column_header(table, column); 262 if (columnHeader && ATK_IS_TEXT(columnHeader)) 263 return atk_text_get_text(ATK_TEXT(columnHeader), 0, -1); 264 265 return 0; 266} 267 268static const gchar* webkitAccessibleTableGetRowDescription(AtkTable* table, gint row) 269{ 270 g_return_val_if_fail(ATK_TABLE(table), 0); 271 returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(table), 0); 272 273 AtkObject* rowHeader = atk_table_get_row_header(table, row); 274 if (rowHeader && ATK_IS_TEXT(rowHeader)) 275 return atk_text_get_text(ATK_TEXT(rowHeader), 0, -1); 276 277 return 0; 278} 279 280void webkitAccessibleTableInterfaceInit(AtkTableIface* iface) 281{ 282 iface->ref_at = webkitAccessibleTableRefAt; 283 iface->get_index_at = webkitAccessibleTableGetIndexAt; 284 iface->get_column_at_index = webkitAccessibleTableGetColumnAtIndex; 285 iface->get_row_at_index = webkitAccessibleTableGetRowAtIndex; 286 iface->get_n_columns = webkitAccessibleTableGetNColumns; 287 iface->get_n_rows = webkitAccessibleTableGetNRows; 288 iface->get_column_extent_at = webkitAccessibleTableGetColumnExtentAt; 289 iface->get_row_extent_at = webkitAccessibleTableGetRowExtentAt; 290 iface->get_column_header = webkitAccessibleTableGetColumnHeader; 291 iface->get_row_header = webkitAccessibleTableGetRowHeader; 292 iface->get_caption = webkitAccessibleTableGetCaption; 293 iface->get_column_description = webkitAccessibleTableGetColumnDescription; 294 iface->get_row_description = webkitAccessibleTableGetRowDescription; 295} 296 297#endif 298