025ef0817ee59c96035c65e850b1b355b0483a2f
[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 0;
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 (accTable->isAccessibilityRenderObject())
62         return toAccessibilityTable(accTable)->cellForColumnAndRow(column, row);
63     return 0;
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 (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
93 static 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
111 static 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
121 static 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
135 static 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
149 static 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
160 static 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
171 static 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
185 static 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
199 static 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
219 static 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
239 static AtkObject* webkitAccessibleTableGetCaption(AtkTable* table)
240 {
241     g_return_val_if_fail(ATK_TABLE(table), nullptr);
242     returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(table), nullptr);
243
244     AccessibilityObject* accTable = core(table);
245     if (accTable->isAccessibilityRenderObject()) {
246         Node* node = accTable->node();
247         if (is<HTMLTableElement>(node)) {
248             HTMLTableCaptionElement* caption = downcast<HTMLTableElement>(*node).caption();
249             if (caption)
250                 return AccessibilityObject::firstAccessibleObjectFromNode(caption->renderer()->element())->wrapper();
251         }
252     }
253     return nullptr;
254 }
255
256 static 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
268 static 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
280 void 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