|
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 "Accessible-inl.h" |
|
10 #include "AccessibleWrap.h" |
|
11 #include "nsAccUtils.h" |
|
12 #include "TableAccessible.h" |
|
13 #include "TableCellAccessible.h" |
|
14 #include "nsMai.h" |
|
15 |
|
16 #include "nsArrayUtils.h" |
|
17 |
|
18 #include "mozilla/Likely.h" |
|
19 |
|
20 using namespace mozilla::a11y; |
|
21 |
|
22 extern "C" { |
|
23 static AtkObject* |
|
24 refAtCB(AtkTable* aTable, gint aRowIdx, gint aColIdx) |
|
25 { |
|
26 AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable)); |
|
27 if (!accWrap || aRowIdx < 0 || aColIdx < 0) |
|
28 return nullptr; |
|
29 |
|
30 Accessible* cell = accWrap->AsTable()->CellAt(aRowIdx, aColIdx); |
|
31 if (!cell) |
|
32 return nullptr; |
|
33 |
|
34 AtkObject* cellAtkObj = AccessibleWrap::GetAtkObject(cell); |
|
35 if (cellAtkObj) |
|
36 g_object_ref(cellAtkObj); |
|
37 |
|
38 return cellAtkObj; |
|
39 } |
|
40 |
|
41 static gint |
|
42 getIndexAtCB(AtkTable* aTable, gint aRowIdx, gint aColIdx) |
|
43 { |
|
44 AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable)); |
|
45 if (!accWrap || aRowIdx < 0 || aColIdx < 0) |
|
46 return -1; |
|
47 |
|
48 return static_cast<gint>(accWrap->AsTable()->CellIndexAt(aRowIdx, aColIdx)); |
|
49 } |
|
50 |
|
51 static gint |
|
52 getColumnAtIndexCB(AtkTable *aTable, gint aIdx) |
|
53 { |
|
54 AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable)); |
|
55 if (!accWrap || aIdx < 0) |
|
56 return -1; |
|
57 |
|
58 return static_cast<gint>(accWrap->AsTable()->ColIndexAt(aIdx)); |
|
59 } |
|
60 |
|
61 static gint |
|
62 getRowAtIndexCB(AtkTable *aTable, gint aIdx) |
|
63 { |
|
64 AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable)); |
|
65 if (!accWrap || aIdx < 0) |
|
66 return -1; |
|
67 |
|
68 return static_cast<gint>(accWrap->AsTable()->RowIndexAt(aIdx)); |
|
69 } |
|
70 |
|
71 static gint |
|
72 getColumnCountCB(AtkTable *aTable) |
|
73 { |
|
74 AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable)); |
|
75 if (!accWrap) |
|
76 return -1; |
|
77 |
|
78 return static_cast<gint>(accWrap->AsTable()->ColCount()); |
|
79 } |
|
80 |
|
81 static gint |
|
82 getRowCountCB(AtkTable *aTable) |
|
83 { |
|
84 AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable)); |
|
85 if (!accWrap) |
|
86 return -1; |
|
87 |
|
88 return static_cast<gint>(accWrap->AsTable()->RowCount()); |
|
89 } |
|
90 |
|
91 static gint |
|
92 getColumnExtentAtCB(AtkTable *aTable, gint aRowIdx, gint aColIdx) |
|
93 { |
|
94 AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable)); |
|
95 if (!accWrap || aRowIdx < 0 || aColIdx < 0) |
|
96 return -1; |
|
97 |
|
98 return static_cast<gint>(accWrap->AsTable()->ColExtentAt(aRowIdx, aColIdx)); |
|
99 } |
|
100 |
|
101 static gint |
|
102 getRowExtentAtCB(AtkTable *aTable, gint aRowIdx, gint aColIdx) |
|
103 { |
|
104 AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable)); |
|
105 if (!accWrap) |
|
106 return -1; |
|
107 |
|
108 return static_cast<gint>(accWrap->AsTable()->RowExtentAt(aRowIdx, aColIdx)); |
|
109 } |
|
110 |
|
111 static AtkObject* |
|
112 getCaptionCB(AtkTable* aTable) |
|
113 { |
|
114 AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable)); |
|
115 if (!accWrap) |
|
116 return nullptr; |
|
117 |
|
118 Accessible* caption = accWrap->AsTable()->Caption(); |
|
119 return caption ? AccessibleWrap::GetAtkObject(caption) : nullptr; |
|
120 } |
|
121 |
|
122 static const gchar* |
|
123 getColumnDescriptionCB(AtkTable *aTable, gint aColumn) |
|
124 { |
|
125 AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable)); |
|
126 if (!accWrap) |
|
127 return nullptr; |
|
128 |
|
129 nsAutoString autoStr; |
|
130 accWrap->AsTable()->ColDescription(aColumn, autoStr); |
|
131 |
|
132 return AccessibleWrap::ReturnString(autoStr); |
|
133 } |
|
134 |
|
135 static AtkObject* |
|
136 getColumnHeaderCB(AtkTable *aTable, gint aColIdx) |
|
137 { |
|
138 AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable)); |
|
139 if (!accWrap) |
|
140 return nullptr; |
|
141 |
|
142 Accessible* cell = accWrap->AsTable()->CellAt(0, aColIdx); |
|
143 if (!cell) |
|
144 return nullptr; |
|
145 |
|
146 // If the cell at the first row is column header then assume it is column |
|
147 // header for all rows, |
|
148 if (cell->Role() == roles::COLUMNHEADER) |
|
149 return AccessibleWrap::GetAtkObject(cell); |
|
150 |
|
151 // otherwise get column header for the data cell at the first row. |
|
152 TableCellAccessible* tableCell = cell->AsTableCell(); |
|
153 if (!tableCell) |
|
154 return nullptr; |
|
155 |
|
156 nsAutoTArray<Accessible*, 10> headerCells; |
|
157 tableCell->ColHeaderCells(&headerCells); |
|
158 if (headerCells.IsEmpty()) |
|
159 return nullptr; |
|
160 |
|
161 return AccessibleWrap::GetAtkObject(headerCells[0]); |
|
162 } |
|
163 |
|
164 static const gchar* |
|
165 getRowDescriptionCB(AtkTable *aTable, gint aRow) |
|
166 { |
|
167 AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable)); |
|
168 if (!accWrap) |
|
169 return nullptr; |
|
170 |
|
171 nsAutoString autoStr; |
|
172 accWrap->AsTable()->RowDescription(aRow, autoStr); |
|
173 |
|
174 return AccessibleWrap::ReturnString(autoStr); |
|
175 } |
|
176 |
|
177 static AtkObject* |
|
178 getRowHeaderCB(AtkTable *aTable, gint aRowIdx) |
|
179 { |
|
180 AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable)); |
|
181 if (!accWrap) |
|
182 return nullptr; |
|
183 |
|
184 Accessible* cell = accWrap->AsTable()->CellAt(aRowIdx, 0); |
|
185 if (!cell) |
|
186 return nullptr; |
|
187 |
|
188 // If the cell at the first column is row header then assume it is row |
|
189 // header for all columns, |
|
190 if (cell->Role() == roles::ROWHEADER) |
|
191 return AccessibleWrap::GetAtkObject(cell); |
|
192 |
|
193 // otherwise get row header for the data cell at the first column. |
|
194 TableCellAccessible* tableCell = cell->AsTableCell(); |
|
195 if (!tableCell) |
|
196 return nullptr; |
|
197 |
|
198 nsAutoTArray<Accessible*, 10> headerCells; |
|
199 tableCell->RowHeaderCells(&headerCells); |
|
200 if (headerCells.IsEmpty()) |
|
201 return nullptr; |
|
202 |
|
203 return AccessibleWrap::GetAtkObject(headerCells[0]); |
|
204 } |
|
205 |
|
206 static AtkObject* |
|
207 getSummaryCB(AtkTable *aTable) |
|
208 { |
|
209 // Neither html:table nor xul:tree nor ARIA grid/tree have an ability to |
|
210 // link an accessible object to specify a summary. There is closes method |
|
211 // in TableAccessible::summary to get a summary as a string which is not |
|
212 // mapped directly to ATK. |
|
213 return nullptr; |
|
214 } |
|
215 |
|
216 static gint |
|
217 getSelectedColumnsCB(AtkTable *aTable, gint** aSelected) |
|
218 { |
|
219 *aSelected = nullptr; |
|
220 |
|
221 AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable)); |
|
222 if (!accWrap) |
|
223 return 0; |
|
224 |
|
225 nsAutoTArray<uint32_t, 10> cols; |
|
226 accWrap->AsTable()->SelectedColIndices(&cols); |
|
227 if (cols.IsEmpty()) |
|
228 return 0; |
|
229 |
|
230 gint* atkColumns = g_new(gint, cols.Length()); |
|
231 if (!atkColumns) { |
|
232 NS_WARNING("OUT OF MEMORY"); |
|
233 return 0; |
|
234 } |
|
235 |
|
236 memcpy(atkColumns, cols.Elements(), cols.Length() * sizeof(uint32_t)); |
|
237 *aSelected = atkColumns; |
|
238 return cols.Length(); |
|
239 } |
|
240 |
|
241 static gint |
|
242 getSelectedRowsCB(AtkTable *aTable, gint **aSelected) |
|
243 { |
|
244 AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable)); |
|
245 if (!accWrap) |
|
246 return 0; |
|
247 |
|
248 nsAutoTArray<uint32_t, 10> rows; |
|
249 accWrap->AsTable()->SelectedRowIndices(&rows); |
|
250 |
|
251 gint* atkRows = g_new(gint, rows.Length()); |
|
252 if (!atkRows) { |
|
253 NS_WARNING("OUT OF MEMORY"); |
|
254 return 0; |
|
255 } |
|
256 |
|
257 memcpy(atkRows, rows.Elements(), rows.Length() * sizeof(uint32_t)); |
|
258 *aSelected = atkRows; |
|
259 return rows.Length(); |
|
260 } |
|
261 |
|
262 static gboolean |
|
263 isColumnSelectedCB(AtkTable *aTable, gint aColIdx) |
|
264 { |
|
265 AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable)); |
|
266 if (!accWrap) |
|
267 return FALSE; |
|
268 |
|
269 return static_cast<gboolean>(accWrap->AsTable()->IsColSelected(aColIdx)); |
|
270 } |
|
271 |
|
272 static gboolean |
|
273 isRowSelectedCB(AtkTable *aTable, gint aRowIdx) |
|
274 { |
|
275 AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable)); |
|
276 if (!accWrap) |
|
277 return FALSE; |
|
278 |
|
279 return static_cast<gboolean>(accWrap->AsTable()->IsRowSelected(aRowIdx)); |
|
280 } |
|
281 |
|
282 static gboolean |
|
283 isCellSelectedCB(AtkTable *aTable, gint aRowIdx, gint aColIdx) |
|
284 { |
|
285 AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable)); |
|
286 if (!accWrap) |
|
287 return FALSE; |
|
288 |
|
289 return static_cast<gboolean>(accWrap->AsTable()-> |
|
290 IsCellSelected(aRowIdx, aColIdx)); |
|
291 } |
|
292 } |
|
293 |
|
294 void |
|
295 tableInterfaceInitCB(AtkTableIface* aIface) |
|
296 { |
|
297 NS_ASSERTION(aIface, "no interface!"); |
|
298 if (MOZ_UNLIKELY(!aIface)) |
|
299 return; |
|
300 |
|
301 aIface->ref_at = refAtCB; |
|
302 aIface->get_index_at = getIndexAtCB; |
|
303 aIface->get_column_at_index = getColumnAtIndexCB; |
|
304 aIface->get_row_at_index = getRowAtIndexCB; |
|
305 aIface->get_n_columns = getColumnCountCB; |
|
306 aIface->get_n_rows = getRowCountCB; |
|
307 aIface->get_column_extent_at = getColumnExtentAtCB; |
|
308 aIface->get_row_extent_at = getRowExtentAtCB; |
|
309 aIface->get_caption = getCaptionCB; |
|
310 aIface->get_column_description = getColumnDescriptionCB; |
|
311 aIface->get_column_header = getColumnHeaderCB; |
|
312 aIface->get_row_description = getRowDescriptionCB; |
|
313 aIface->get_row_header = getRowHeaderCB; |
|
314 aIface->get_summary = getSummaryCB; |
|
315 aIface->get_selected_columns = getSelectedColumnsCB; |
|
316 aIface->get_selected_rows = getSelectedRowsCB; |
|
317 aIface->is_column_selected = isColumnSelectedCB; |
|
318 aIface->is_row_selected = isRowSelectedCB; |
|
319 aIface->is_selected = isCellSelectedCB; |
|
320 } |