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