1 /*  This file is part of the GtkHTML library.
2  *
3  *  Copyright 2002 Ximian, Inc.
4  *
5  *  Author: Radek Doulik
6  *
7  *
8  *  This library is free software; you can redistribute it and/or
9  *  modify it under the terms of the GNU Library General Public
10  *  License as published by the Free Software Foundation; either
11  *  version 2 of the License, or (at your option) any later version.
12  *
13  *  This library is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  *  Library General Public License for more details.
17  *
18  *  You should have received a copy of the GNU Library General Public License
19  *  along with this library; see the file COPYING.LIB.  If not, write to
20  *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21  *  Boston, MA 02110-1301, USA.
22  */
23 
24 #include <config.h>
25 #include <atk/atktable.h>
26 
27 #include "htmltable.h"
28 #include "htmltablecell.h"
29 #include "gtkhtml.h"
30 #include "htmlengine.h"
31 
32 #include "html.h"
33 #include "object.h"
34 #include "table.h"
35 #include "utils.h"
36 
37 static void html_a11y_table_class_init    (HTMLA11YTableClass *klass);
38 static void html_a11y_table_init          (HTMLA11YTable *a11y_table);
39 static void atk_table_interface_init      (AtkTableIface *iface);
40 
41 static AtkObject * html_a11y_table_ref_at (AtkTable *table, gint row, gint column);
42 static gint html_a11y_table_get_index_at (AtkTable *table, gint row, gint column);
43 static gint html_a11y_table_get_column_at_index (AtkTable *table, gint index);
44 static gint html_a11y_table_get_row_at_index (AtkTable *table, gint index);
45 static gint html_a11y_table_get_n_columns (AtkTable *table);
46 static gint html_a11y_table_get_n_rows (AtkTable *table);
47 static gint html_a11y_table_get_column_extent_at (AtkTable *table, gint row, gint column);
48 static gint html_a11y_table_get_row_extent_at (AtkTable *table, gint row, gint column);
49 static AtkObject * html_a11y_table_get_column_header (AtkTable *table, gint column);
50 static AtkObject * html_a11y_table_get_row_header (AtkTable *table, gint row);
51 
52 static AtkObjectClass *parent_class = NULL;
53 
54 GType
html_a11y_table_get_type(void)55 html_a11y_table_get_type (void)
56 {
57 	static GType type = 0;
58 
59 	if (!type) {
60 		static const GTypeInfo tinfo = {
61 			sizeof (HTMLA11YTableClass),
62 			NULL,                                                      /* base init */
63 			NULL,                                                      /* base finalize */
64 			(GClassInitFunc) html_a11y_table_class_init,           /* class init */
65 			NULL,                                                      /* class finalize */
66 			NULL,                                                      /* class data */
67 			sizeof (HTMLA11YTable),                                /* instance size */
68 			0,                                                         /* nb preallocs */
69 			(GInstanceInitFunc) html_a11y_table_init,              /* instance init */
70 			NULL                                                       /* value table */
71 		};
72 
73 		static const GInterfaceInfo atk_table_info = {
74 			(GInterfaceInitFunc) atk_table_interface_init,
75 			(GInterfaceFinalizeFunc) NULL,
76 			NULL
77 		};
78 
79 		type = g_type_register_static (G_TYPE_HTML_A11Y, "HTMLA11YTable", &tinfo, 0);
80 		g_type_add_interface_static (type, ATK_TYPE_TABLE, &atk_table_info);
81 	}
82 
83 	return type;
84 }
85 
86 static void
atk_table_interface_init(AtkTableIface * iface)87 atk_table_interface_init (AtkTableIface *iface)
88 {
89 	g_return_if_fail (iface != NULL);
90 
91 	iface->ref_at = html_a11y_table_ref_at;
92 	iface->get_index_at = html_a11y_table_get_index_at;
93 	iface->get_column_at_index = html_a11y_table_get_column_at_index;
94 	iface->get_row_at_index = html_a11y_table_get_row_at_index;
95 	iface->get_n_columns = html_a11y_table_get_n_columns;
96 	iface->get_n_rows = html_a11y_table_get_n_rows;
97 	iface->get_column_extent_at = html_a11y_table_get_column_extent_at;
98 	iface->get_row_extent_at = html_a11y_table_get_row_extent_at;
99 	iface->get_column_header = html_a11y_table_get_column_header;
100 	iface->get_row_header = html_a11y_table_get_row_header;
101 }
102 
103 static void
html_a11y_table_finalize(GObject * obj)104 html_a11y_table_finalize (GObject *obj)
105 {
106 	G_OBJECT_CLASS (parent_class)->finalize (obj);
107 }
108 
109 static void
html_a11y_table_initialize(AtkObject * obj,gpointer data)110 html_a11y_table_initialize (AtkObject *obj,
111                             gpointer data)
112 {
113 	/* printf ("html_a11y_table_initialize\n"); */
114 
115 	if (ATK_OBJECT_CLASS (parent_class)->initialize)
116 		ATK_OBJECT_CLASS (parent_class)->initialize (obj, data);
117 }
118 
119 static void
html_a11y_table_class_init(HTMLA11YTableClass * klass)120 html_a11y_table_class_init (HTMLA11YTableClass *klass)
121 {
122 	GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
123 	AtkObjectClass *atk_class = ATK_OBJECT_CLASS (klass);
124 
125 	parent_class = g_type_class_peek_parent (klass);
126 
127 	atk_class->initialize = html_a11y_table_initialize;
128 	gobject_class->finalize = html_a11y_table_finalize;
129 }
130 
131 static void
html_a11y_table_init(HTMLA11YTable * a11y_table)132 html_a11y_table_init (HTMLA11YTable *a11y_table)
133 {
134 }
135 
136 AtkObject *
html_a11y_table_new(HTMLObject * html_obj)137 html_a11y_table_new (HTMLObject *html_obj)
138 {
139 	GObject *object;
140 	AtkObject *accessible;
141 
142 	g_return_val_if_fail (HTML_IS_TABLE (html_obj), NULL);
143 
144 	object = g_object_new (G_TYPE_HTML_A11Y_TABLE, NULL);
145 
146 	accessible = ATK_OBJECT (object);
147 	atk_object_initialize (accessible, html_obj);
148 
149 	accessible->role = ATK_ROLE_TABLE;
150 
151 	/* printf ("created new html accessible table object\n"); */
152 
153 	return accessible;
154 }
155 
156 static gboolean
is_valid(AtkObject * table)157 is_valid (AtkObject *table)
158 {
159 	GtkHTMLA11Y * htmla11y = html_a11y_get_gtkhtml_parent (HTML_A11Y (table));
160 	GtkHTML *html = GTK_HTML_A11Y_GTKHTML (htmla11y);
161 	AtkStateSet *ss;
162 
163 	HTMLTable *to = HTML_TABLE (HTML_A11Y_HTML (table));
164 	if (!htmla11y)
165 		return FALSE;
166 
167 	if (!to)
168 		return FALSE;
169 
170 	if (html->engine->parsing)
171 		return FALSE;
172 
173 	ss = atk_object_ref_state_set (ATK_OBJECT (htmla11y));
174 	if (atk_state_set_contains_state (ss, ATK_STATE_DEFUNCT)) {
175 		g_object_unref (ss);
176 		return FALSE;
177 	}
178 	g_object_unref (ss);
179 
180 	return TRUE;
181 }
182 
183 /*
184  * AtkTable interface
185  */
186 
187 static AtkObject *
html_a11y_table_ref_at(AtkTable * table,gint row,gint column)188 html_a11y_table_ref_at (AtkTable *table,
189                         gint row,
190                         gint column)
191 {
192 	AtkObject *accessible = NULL;
193 	HTMLTable *to = HTML_TABLE (HTML_A11Y_HTML (table));
194 	HTMLTableCell *cell;
195 
196 	if (!is_valid (ATK_OBJECT (table)))
197 		return NULL;
198 
199 	g_return_val_if_fail (row < to->totalRows, NULL);
200 	g_return_val_if_fail (column < to->totalCols, NULL);
201 
202 	cell = to->cells[row][column];
203 
204 	if (cell) {
205 		accessible = html_utils_get_accessible (HTML_OBJECT (cell), ATK_OBJECT (table));
206 		if (accessible)
207 			g_object_ref (accessible);
208 	}
209 
210 	return accessible;
211 }
212 
213 static gint
html_a11y_table_get_index_at(AtkTable * table,gint row,gint column)214 html_a11y_table_get_index_at (AtkTable *table,
215                               gint row,
216                               gint column)
217 {
218 	HTMLTable *to = HTML_TABLE (HTML_A11Y_HTML (table));
219 
220 	if (!is_valid (ATK_OBJECT (table)))
221 		return -1;
222 
223 	g_return_val_if_fail (row < to->totalRows, -1);
224 	g_return_val_if_fail (column < to->totalCols, -1);
225 	g_return_val_if_fail (to->cells[row][column], -1);
226 
227 	return html_object_get_child_index (HTML_OBJECT (to), HTML_OBJECT (to->cells[row][column]));
228 }
229 
230 static gint
html_a11y_table_get_column_at_index(AtkTable * table,gint index)231 html_a11y_table_get_column_at_index (AtkTable *table,
232                                      gint index)
233 {
234 	HTMLTable *to = HTML_TABLE (HTML_A11Y_HTML (table));
235 	HTMLTableCell *cell;
236 
237 	if (!is_valid (ATK_OBJECT (table)))
238 		return -1;
239 
240 	cell = HTML_TABLE_CELL (html_object_get_child (HTML_OBJECT (to), index));
241 
242 	return cell ? cell->col : -1;
243 }
244 
245 static gint
html_a11y_table_get_row_at_index(AtkTable * table,gint index)246 html_a11y_table_get_row_at_index (AtkTable *table,
247                                   gint index)
248 {
249 	HTMLTable *to = HTML_TABLE (HTML_A11Y_HTML (table));
250 	HTMLTableCell *cell;
251 
252 	if (!is_valid (ATK_OBJECT (table)))
253 		return -1;
254 
255 	cell = HTML_TABLE_CELL (html_object_get_child (HTML_OBJECT (to), index));
256 
257 	return cell ? cell->row : -1;
258 }
259 
260 static gint
html_a11y_table_get_n_columns(AtkTable * table)261 html_a11y_table_get_n_columns (AtkTable *table)
262 {
263 	HTMLTable *to = HTML_TABLE (HTML_A11Y_HTML (table));
264 
265 	if (!is_valid (ATK_OBJECT (table)))
266 		return -1;
267 
268 	return to->totalCols;
269 }
270 
271 static gint
html_a11y_table_get_n_rows(AtkTable * table)272 html_a11y_table_get_n_rows (AtkTable *table)
273 {
274 	HTMLTable *to = HTML_TABLE (HTML_A11Y_HTML (table));
275 
276 	if (!is_valid (ATK_OBJECT (table)))
277 		return -1;
278 
279 	return to->totalRows;
280 }
281 
282 static gint
html_a11y_table_get_column_extent_at(AtkTable * table,gint row,gint column)283 html_a11y_table_get_column_extent_at (AtkTable *table,
284                                       gint row,
285                                       gint column)
286 {
287 	HTMLTable *to = HTML_TABLE (HTML_A11Y_HTML (table));
288 
289 	if (!is_valid (ATK_OBJECT (table)))
290 		return -1;
291 
292 	g_return_val_if_fail (row < to->totalRows, -1);
293 	g_return_val_if_fail (column < to->totalCols, -1);
294 	g_return_val_if_fail (to->cells[row][column], -1);
295 
296 	return to->cells[row][column]->cspan;
297 }
298 
299 static gint
html_a11y_table_get_row_extent_at(AtkTable * table,gint row,gint column)300 html_a11y_table_get_row_extent_at (AtkTable *table,
301                                    gint row,
302                                    gint column)
303 {
304 	HTMLTable *to = HTML_TABLE (HTML_A11Y_HTML (table));
305 
306 	if (!is_valid (ATK_OBJECT (table)))
307 		return -1;
308 
309 	g_return_val_if_fail (row < to->totalRows, -1);
310 	g_return_val_if_fail (column < to->totalCols, -1);
311 	g_return_val_if_fail (to->cells[row][column], -1);
312 
313 	return to->cells[row][column]->rspan;
314 }
315 
316 static AtkObject *
html_a11y_table_get_column_header(AtkTable * table,gint column)317 html_a11y_table_get_column_header (AtkTable *table,
318                                    gint column)
319 {
320 	HTMLTable *to = HTML_TABLE (HTML_A11Y_HTML (table));
321 
322 	if (!is_valid (ATK_OBJECT (table)))
323 		return NULL;
324 
325 	g_return_val_if_fail (column < to->totalCols, NULL);
326 	g_return_val_if_fail (to->cells[0][column], NULL);
327 
328 	return to->cells[0][column]->heading
329 		? html_utils_get_accessible (HTML_OBJECT (to->cells[0][column]), ATK_OBJECT (table)) : NULL;
330 }
331 
332 static AtkObject *
html_a11y_table_get_row_header(AtkTable * table,gint row)333 html_a11y_table_get_row_header (AtkTable *table,
334                                 gint row)
335 {
336 	HTMLTable *to = HTML_TABLE (HTML_A11Y_HTML (table));
337 
338 	if (!is_valid (ATK_OBJECT (table)))
339 		return NULL;
340 
341 	g_return_val_if_fail (row < to->totalRows, NULL);
342 	g_return_val_if_fail (to->cells[row][0], NULL);
343 
344 	return to->cells[row][0]->heading
345 		? html_utils_get_accessible (HTML_OBJECT (to->cells[row][0]), ATK_OBJECT (table)) : NULL;
346 }
347 
348 /* unsupported calls
349  *
350  *   AtkObject*
351  *                     (* get_caption)              (AtkTable      *table);
352  *   const gchar *     (* get_column_description)   (AtkTable      *table,
353  *                                                   gint          column);
354  *   const gchar *     (* get_row_description)      (AtkTable      *table,
355  *                                                   gint          row);
356  *   AtkObject*        (* get_summary)              (AtkTable      *table);
357  *   void              (* set_caption)              (AtkTable      *table,
358  *                                                   AtkObject     *caption);
359  *   void              (* set_column_description)   (AtkTable      *table,
360  *                                                   gint          column,
361  *                                                   const gchar   *description);
362  *   void              (* set_column_header)        (AtkTable      *table,
363  *                                                   gint          column,
364  *                                                   AtkObject     *header);
365  *   void              (* set_row_description)      (AtkTable      *table,
366  *                                                   gint          row,
367  *                                                   const gchar   *description);
368  *   void              (* set_row_header)           (AtkTable      *table,
369  *                                                   gint          row,
370  *                                                   AtkObject     *header);
371  *   void              (* set_summary)              (AtkTable      *table,
372  *                                                   AtkObject     *accessible);
373  *   gint              (* get_selected_columns)     (AtkTable      *table,
374  *                                                   gint          **selected);
375  *   gint              (* get_selected_rows)        (AtkTable      *table,
376  *                                                   gint          **selected);
377  *   gboolean          (* is_column_selected)       (AtkTable      *table,
378  *                                                   gint          column);
379  *   gboolean          (* is_row_selected)          (AtkTable      *table,
380  *                                                   gint          row);
381  *   gboolean          (* is_selected)              (AtkTable      *table,
382  *                                                   gint          row,
383  *                                                   gint          column);
384  *   gboolean          (* add_row_selection)        (AtkTable      *table,
385  *                                                   gint          row);
386  *   gboolean          (* remove_row_selection)     (AtkTable      *table,
387  *                                                   gint          row);
388  *   gboolean          (* add_column_selection)     (AtkTable      *table,
389  *                                                   gint          column);
390  *   gboolean          (* remove_column_selection)  (AtkTable      *table,
391  *                                                   gint          column);
392  */
393