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