1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7 #include "InterfaceInitFuncs.h"
8
9 #include "LocalAccessible-inl.h"
10 #include "AccessibleWrap.h"
11 #include "nsAccUtils.h"
12 #include "TableAccessible.h"
13 #include "TableCellAccessible.h"
14 #include "nsMai.h"
15 #include "RemoteAccessible.h"
16 #include "nsArrayUtils.h"
17
18 #include "mozilla/Likely.h"
19
20 using namespace mozilla::a11y;
21
22 extern "C" {
refAtCB(AtkTable * aTable,gint aRowIdx,gint aColIdx)23 static AtkObject* refAtCB(AtkTable* aTable, gint aRowIdx, gint aColIdx) {
24 if (aRowIdx < 0 || aColIdx < 0) {
25 return nullptr;
26 }
27
28 AtkObject* cellAtkObj = nullptr;
29 AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
30 if (accWrap) {
31 LocalAccessible* cell = accWrap->AsTable()->CellAt(aRowIdx, aColIdx);
32 if (!cell) {
33 return nullptr;
34 }
35
36 cellAtkObj = AccessibleWrap::GetAtkObject(cell);
37 } else if (RemoteAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
38 RemoteAccessible* cell = proxy->TableCellAt(aRowIdx, aColIdx);
39 if (!cell) {
40 return nullptr;
41 }
42
43 cellAtkObj = GetWrapperFor(cell);
44 }
45
46 if (cellAtkObj) {
47 g_object_ref(cellAtkObj);
48 }
49
50 return cellAtkObj;
51 }
52
getIndexAtCB(AtkTable * aTable,gint aRowIdx,gint aColIdx)53 static gint getIndexAtCB(AtkTable* aTable, gint aRowIdx, gint aColIdx) {
54 if (aRowIdx < 0 || aColIdx < 0) {
55 return -1;
56 }
57
58 AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
59 if (accWrap) {
60 return static_cast<gint>(accWrap->AsTable()->CellIndexAt(aRowIdx, aColIdx));
61 }
62
63 if (RemoteAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
64 return static_cast<gint>(proxy->TableCellIndexAt(aRowIdx, aColIdx));
65 }
66
67 return -1;
68 }
69
getColumnAtIndexCB(AtkTable * aTable,gint aIdx)70 static gint getColumnAtIndexCB(AtkTable* aTable, gint aIdx) {
71 if (aIdx < 0) {
72 return -1;
73 }
74
75 AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
76 if (accWrap) {
77 return static_cast<gint>(accWrap->AsTable()->ColIndexAt(aIdx));
78 }
79
80 if (RemoteAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
81 return static_cast<gint>(proxy->TableColumnIndexAt(aIdx));
82 }
83
84 return -1;
85 }
86
getRowAtIndexCB(AtkTable * aTable,gint aIdx)87 static gint getRowAtIndexCB(AtkTable* aTable, gint aIdx) {
88 if (aIdx < 0) {
89 return -1;
90 }
91
92 AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
93 if (accWrap) {
94 return static_cast<gint>(accWrap->AsTable()->RowIndexAt(aIdx));
95 }
96
97 if (RemoteAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
98 return static_cast<gint>(proxy->TableRowIndexAt(aIdx));
99 }
100
101 return -1;
102 }
103
getColumnCountCB(AtkTable * aTable)104 static gint getColumnCountCB(AtkTable* aTable) {
105 AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
106 if (accWrap) {
107 return static_cast<gint>(accWrap->AsTable()->ColCount());
108 }
109
110 if (RemoteAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
111 return static_cast<gint>(proxy->TableColumnCount());
112 }
113
114 return -1;
115 }
116
getRowCountCB(AtkTable * aTable)117 static gint getRowCountCB(AtkTable* aTable) {
118 AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
119 if (accWrap) {
120 return static_cast<gint>(accWrap->AsTable()->RowCount());
121 }
122
123 if (RemoteAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
124 return static_cast<gint>(proxy->TableRowCount());
125 }
126
127 return -1;
128 }
129
getColumnExtentAtCB(AtkTable * aTable,gint aRowIdx,gint aColIdx)130 static gint getColumnExtentAtCB(AtkTable* aTable, gint aRowIdx, gint aColIdx) {
131 if (aRowIdx < 0 || aColIdx < 0) {
132 return -1;
133 }
134
135 AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
136 if (accWrap) {
137 return static_cast<gint>(accWrap->AsTable()->ColExtentAt(aRowIdx, aColIdx));
138 }
139
140 if (RemoteAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
141 return static_cast<gint>(proxy->TableColumnExtentAt(aRowIdx, aColIdx));
142 }
143
144 return -1;
145 }
146
getRowExtentAtCB(AtkTable * aTable,gint aRowIdx,gint aColIdx)147 static gint getRowExtentAtCB(AtkTable* aTable, gint aRowIdx, gint aColIdx) {
148 AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
149 if (accWrap) {
150 return static_cast<gint>(accWrap->AsTable()->RowExtentAt(aRowIdx, aColIdx));
151 }
152
153 if (RemoteAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
154 return static_cast<gint>(proxy->TableRowExtentAt(aRowIdx, aColIdx));
155 }
156
157 return -1;
158 }
159
getCaptionCB(AtkTable * aTable)160 static AtkObject* getCaptionCB(AtkTable* aTable) {
161 AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
162 if (accWrap) {
163 LocalAccessible* caption = accWrap->AsTable()->Caption();
164 return caption ? AccessibleWrap::GetAtkObject(caption) : nullptr;
165 }
166
167 if (RemoteAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
168 RemoteAccessible* caption = proxy->TableCaption();
169 return caption ? GetWrapperFor(caption) : nullptr;
170 }
171
172 return nullptr;
173 }
174
getColumnDescriptionCB(AtkTable * aTable,gint aColumn)175 static const gchar* getColumnDescriptionCB(AtkTable* aTable, gint aColumn) {
176 nsAutoString autoStr;
177 AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
178 if (accWrap) {
179 accWrap->AsTable()->ColDescription(aColumn, autoStr);
180 } else if (RemoteAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
181 proxy->TableColumnDescription(aColumn, autoStr);
182 } else {
183 return nullptr;
184 }
185
186 return AccessibleWrap::ReturnString(autoStr);
187 }
188
getColumnHeaderCB(AtkTable * aTable,gint aColIdx)189 static AtkObject* getColumnHeaderCB(AtkTable* aTable, gint aColIdx) {
190 AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
191 if (accWrap) {
192 LocalAccessible* header =
193 AccessibleWrap::GetColumnHeader(accWrap->AsTable(), aColIdx);
194 return header ? AccessibleWrap::GetAtkObject(header) : nullptr;
195 }
196
197 if (RemoteAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
198 RemoteAccessible* header = proxy->AtkTableColumnHeader(aColIdx);
199 return header ? GetWrapperFor(header) : nullptr;
200 }
201
202 return nullptr;
203 }
204
getRowDescriptionCB(AtkTable * aTable,gint aRow)205 static const gchar* getRowDescriptionCB(AtkTable* aTable, gint aRow) {
206 nsAutoString autoStr;
207 AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
208 if (accWrap) {
209 accWrap->AsTable()->RowDescription(aRow, autoStr);
210 } else if (RemoteAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
211 proxy->TableRowDescription(aRow, autoStr);
212 } else {
213 return nullptr;
214 }
215
216 return AccessibleWrap::ReturnString(autoStr);
217 }
218
getRowHeaderCB(AtkTable * aTable,gint aRowIdx)219 static AtkObject* getRowHeaderCB(AtkTable* aTable, gint aRowIdx) {
220 AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
221 if (accWrap) {
222 LocalAccessible* header =
223 AccessibleWrap::GetRowHeader(accWrap->AsTable(), aRowIdx);
224 return header ? AccessibleWrap::GetAtkObject(header) : nullptr;
225 }
226
227 if (RemoteAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
228 RemoteAccessible* header = proxy->AtkTableRowHeader(aRowIdx);
229 return header ? GetWrapperFor(header) : nullptr;
230 }
231
232 return nullptr;
233 }
234
getSummaryCB(AtkTable * aTable)235 static AtkObject* getSummaryCB(AtkTable* aTable) {
236 // Neither html:table nor xul:tree nor ARIA grid/tree have an ability to
237 // link an accessible object to specify a summary. There is closes method
238 // in TableAccessible::summary to get a summary as a string which is not
239 // mapped directly to ATK.
240 return nullptr;
241 }
242
getSelectedColumnsCB(AtkTable * aTable,gint ** aSelected)243 static gint getSelectedColumnsCB(AtkTable* aTable, gint** aSelected) {
244 *aSelected = nullptr;
245
246 AutoTArray<uint32_t, 10> cols;
247 AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
248 if (accWrap) {
249 accWrap->AsTable()->SelectedColIndices(&cols);
250 } else if (RemoteAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
251 proxy->TableSelectedColumnIndices(&cols);
252 } else {
253 return 0;
254 }
255
256 if (cols.IsEmpty()) return 0;
257
258 gint* atkColumns = g_new(gint, cols.Length());
259 if (!atkColumns) {
260 NS_WARNING("OUT OF MEMORY");
261 return 0;
262 }
263
264 memcpy(atkColumns, cols.Elements(), cols.Length() * sizeof(uint32_t));
265 *aSelected = atkColumns;
266 return cols.Length();
267 }
268
getSelectedRowsCB(AtkTable * aTable,gint ** aSelected)269 static gint getSelectedRowsCB(AtkTable* aTable, gint** aSelected) {
270 AutoTArray<uint32_t, 10> rows;
271 AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
272 if (accWrap) {
273 accWrap->AsTable()->SelectedRowIndices(&rows);
274 } else if (RemoteAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
275 proxy->TableSelectedRowIndices(&rows);
276 } else {
277 return 0;
278 }
279
280 gint* atkRows = g_new(gint, rows.Length());
281 if (!atkRows) {
282 NS_WARNING("OUT OF MEMORY");
283 return 0;
284 }
285
286 memcpy(atkRows, rows.Elements(), rows.Length() * sizeof(uint32_t));
287 *aSelected = atkRows;
288 return rows.Length();
289 }
290
isColumnSelectedCB(AtkTable * aTable,gint aColIdx)291 static gboolean isColumnSelectedCB(AtkTable* aTable, gint aColIdx) {
292 AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
293 if (accWrap) {
294 return static_cast<gboolean>(accWrap->AsTable()->IsColSelected(aColIdx));
295 }
296 if (RemoteAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
297 return static_cast<gboolean>(proxy->TableColumnSelected(aColIdx));
298 }
299
300 return FALSE;
301 }
302
isRowSelectedCB(AtkTable * aTable,gint aRowIdx)303 static gboolean isRowSelectedCB(AtkTable* aTable, gint aRowIdx) {
304 AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
305 if (accWrap) {
306 return static_cast<gboolean>(accWrap->AsTable()->IsRowSelected(aRowIdx));
307 }
308 if (RemoteAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
309 return static_cast<gboolean>(proxy->TableRowSelected(aRowIdx));
310 }
311
312 return FALSE;
313 }
314
isCellSelectedCB(AtkTable * aTable,gint aRowIdx,gint aColIdx)315 static gboolean isCellSelectedCB(AtkTable* aTable, gint aRowIdx, gint aColIdx) {
316 AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
317 if (accWrap) {
318 return static_cast<gboolean>(
319 accWrap->AsTable()->IsCellSelected(aRowIdx, aColIdx));
320 }
321 if (RemoteAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
322 return static_cast<gboolean>(proxy->TableCellSelected(aRowIdx, aColIdx));
323 }
324
325 return FALSE;
326 }
327 }
328
tableInterfaceInitCB(AtkTableIface * aIface)329 void tableInterfaceInitCB(AtkTableIface* aIface) {
330 NS_ASSERTION(aIface, "no interface!");
331 if (MOZ_UNLIKELY(!aIface)) return;
332
333 aIface->ref_at = refAtCB;
334 aIface->get_index_at = getIndexAtCB;
335 aIface->get_column_at_index = getColumnAtIndexCB;
336 aIface->get_row_at_index = getRowAtIndexCB;
337 aIface->get_n_columns = getColumnCountCB;
338 aIface->get_n_rows = getRowCountCB;
339 aIface->get_column_extent_at = getColumnExtentAtCB;
340 aIface->get_row_extent_at = getRowExtentAtCB;
341 aIface->get_caption = getCaptionCB;
342 aIface->get_column_description = getColumnDescriptionCB;
343 aIface->get_column_header = getColumnHeaderCB;
344 aIface->get_row_description = getRowDescriptionCB;
345 aIface->get_row_header = getRowHeaderCB;
346 aIface->get_summary = getSummaryCB;
347 aIface->get_selected_columns = getSelectedColumnsCB;
348 aIface->get_selected_rows = getSelectedRowsCB;
349 aIface->is_column_selected = isColumnSelectedCB;
350 aIface->is_row_selected = isRowSelectedCB;
351 aIface->is_selected = isCellSelectedCB;
352 }
353