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