1 /*
2 * AT-SPI - Assistive Technology Service Provider Interface
3 * (Gnome Accessibility Project; https://wiki.gnome.org/Accessibility)
4 *
5 * Copyright (c) 2014 Samsung Electronics Co., Ltd.
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
21 */
22
23 #include <stdlib.h>
24 #include <string.h>
25 #include <glib.h>
26 #include <libxml/parser.h>
27 #include <libxml/tree.h>
28
29 #include "my-atk.h"
30
31 #define ACCESSIBLE_NODE ((const xmlChar *) "accessible")
32 #define ACC_ACTION_NODE ((const xmlChar *) "accessible_action")
33 #define ACC_COMPONENT_NODE ((const xmlChar *) "accessible_component")
34 #define ACC_DOCUMENT_NODE ((const xmlChar *) "accessible_document")
35 #define ACC_HYPERLINK_NODE ((const xmlChar *) "accessible_hyperlink")
36 #define ACC_HYPERTEXT_NODE ((const xmlChar *) "accessible_hypertext")
37 #define ACC_IMAGE_NODE ((const xmlChar *) "accessible_image")
38 #define ACC_TABLE_NODE ((const xmlChar *) "accessible_table")
39 #define ACC_TABLE_CELL_NODE ((const xmlChar *) "accessible_table_cell")
40 #define ACC_EDIT_TEXT_NODE ((const xmlChar *) "accessible_editable_text")
41 #define ACC_TEXT_NODE ((const xmlChar *) "accessible_text")
42 #define ACC_SELECTION_NODE ((const xmlChar *) "accessible_selection")
43 #define ACC_VALUE_NODE ((const xmlChar *) "accessible_value")
44 #define ACTION_NODE ((const xmlChar *) "action")
45 #define DOCUMENT_NODE ((const xmlChar *) "document")
46 #define INTERFACE_NODE ((const xmlChar *) "interface")
47 #define RELATION_NODE ((const xmlChar *) "relation")
48 #define STATE_NODE ((const xmlChar *) "state")
49 #define COMPONENT_NODE ((const xmlChar *) "component")
50 #define HYPERLINK_NODE ((const xmlChar *) "hyperlink")
51 #define HYPERTEXT_NODE ((const xmlChar *) "hypertext")
52 #define IMAGE_NODE ((const xmlChar *) "image")
53 #define TABLE_NODE ((const xmlChar *) "table")
54 #define TABLE_CELL_NODE ((const xmlChar *) "table_cell")
55 #define TEXT_NODE ((const xmlChar *) "text_node")
56 #define VALUE_NODE ((const xmlChar *) "value_node")
57 #define SELECT_NODE ((const xmlChar *) "select_node")
58
59 #define NAME_ATTR ((const xmlChar *) "name")
60 #define DESC_ATTR ((const xmlChar *) "description")
61 #define ROLE_ATTR ((const xmlChar *) "role")
62 #define MIN_ATTR ((const xmlChar *) "min")
63 #define MAX_ATTR ((const xmlChar *) "max")
64 #define CURRENT_ATTR ((const xmlChar *) "current")
65 #define STEP_ATTR ((const xmlChar *) "step")
66 #define COL_HEADER_ATTR ((const xmlChar *) "col_header")
67 #define ROW_HEADER_ATTR ((const xmlChar *) "row_header")
68 #define COL_DESC_ATTR ((const xmlChar *) "col_desc")
69 #define ROW_DESC_ATTR ((const xmlChar *) "row_desc")
70 #define SELECTED_ATTR ((const xmlChar *) "selected")
71 #define SELECTED_COL_ATTR ((const xmlChar *) "selected_col")
72 #define RELATION_TYPE_ATTR ((const xmlChar *) "relation_type")
73 #define RELATION_TARGET_NAME_ATTR ((const xmlChar *) "target_name")
74 #define STATE_TYPE_ATTR ((const xmlChar *) "state_enum")
75 #define ACTION_NAME_ATTR ((const xmlChar *) "action_name")
76 #define ACTION_DES_ATTR ((const xmlChar *) "action_description")
77 #define ACTION_KEY_BIND_ATTR ((const xmlChar *) "key_binding")
78 #define COMP_X_ATTR ((const xmlChar *) "x")
79 #define COMP_Y_ATTR ((const xmlChar *) "y")
80 #define COMP_WIDTH_ATTR ((const xmlChar *) "width")
81 #define COMP_HEIGHT_ATTR ((const xmlChar *) "height")
82 #define COMP_LAYER_ATTR ((const xmlChar *) "layer")
83 #define COMP_ZORDER_ATTR ((const xmlChar *) "zorder")
84 #define COMP_ALPHA_ATTR ((const xmlChar *) "alpha")
85 #define IMAGE_DES_ATTR ((const xmlChar *) "image_description")
86 #define IMAGE_LOCALE_ATTR ((const xmlChar *) "image_locale")
87 #define TEXT_TEXT_ATTR ((const xmlChar *) "text")
88 #define TEXT_BOLD_ATTR ((const xmlChar *) "bold_text")
89 #define TEXT_UNDERLINE_ATTR ((const xmlChar *) "underline_text")
90 #define TEXT_DUMMY_ATTR ((const xmlChar *) "dummy_text")
91 #define START_ATTR ((const xmlChar *) "start")
92 #define END_ATTR ((const xmlChar *) "end")
93 #define LINK_ATTR ((const xmlChar *) "link")
94 #define CELL_X_ATTR ((const xmlChar *) "cell_x")
95 #define CELL_Y_ATTR ((const xmlChar *) "cell_y")
96 #define ROW_SPAN_ATTR ((const xmlChar *) "row_span")
97 #define COLUMN_SPAN_ATTR ((const xmlChar *) "column_span")
98 #define SELECT_ATTR ((const xmlChar *) "selected")
99 #define PAGE_ATTR ((const xmlChar *) "page_no")
100 #define PAGE_NUM_ATTR ((const xmlChar *) "page_number")
101
102 MyAtkObject *relation_target = NULL;
103
atof_get_prop(xmlNode * node,const xmlChar * attr)104 static double atof_get_prop (xmlNode *node, const xmlChar *attr)
105 {
106 double ret;
107 xmlChar *str = xmlGetProp (node, attr);
108 if (!str)
109 return 0;
110 ret = atof ((const char *)str);
111 xmlFree(str);
112
113 return ret;
114 }
115
atoi_get_prop(xmlNode * node,const xmlChar * attr)116 static int atoi_get_prop (xmlNode *node, const xmlChar *attr)
117 {
118 int ret;
119 xmlChar *str = xmlGetProp (node, attr);
120 if (!str)
121 return 0;
122 ret = atoi ((const char *)str);
123 xmlFree(str);
124
125 return ret;
126 }
127
128 static AtkAttribute *
get_atk_attribute(xmlNode * node,const xmlChar * attr)129 get_atk_attribute (xmlNode *node, const xmlChar *attr)
130 {
131 xmlChar *str;
132 AtkAttribute *tmp = g_malloc (sizeof (AtkAttribute));
133
134 if (!tmp)
135 return NULL;
136
137 str = xmlGetProp (node, attr);
138 tmp->name = g_strdup ((const char *)attr);
139 tmp->value = g_strdup ((const char *)str);
140
141 free (str);
142 return tmp;
143 }
144
145 static gpointer
create_atk_object_from_element(xmlNode * element)146 create_atk_object_from_element (xmlNode *element)
147 {
148 xmlNode *child_node;
149 xmlNode *child_node2;
150
151 gpointer obj;
152 gpointer child_obj = NULL;
153 AtkRelationSet *relation_set = NULL;
154 AtkObject *array[1];
155 AtkRelation *relation;
156 AtkStateSet *state_set = NULL;
157 AtkStateType state_type;
158
159 xmlChar *name;
160 xmlChar *description;
161 xmlChar *state_enum;
162 xmlChar *role;
163 gint relation_type;
164 xmlChar *relation_target_name;
165 xmlChar *action_name;
166 xmlChar *action_des;
167 xmlChar *action_key_bind;
168 xmlChar *image_des;
169 xmlChar *image_locale;
170 xmlChar *text;
171 gint x_size, y_size;
172 gint width, height;
173 gint x_extent, y_extent, w_extent, h_extent;
174 name = xmlGetProp (element, NAME_ATTR);
175 description = xmlGetProp (element, DESC_ATTR);
176 role = xmlGetProp (element, ROLE_ATTR);
177 GType type = MY_TYPE_ATK_OBJECT;
178 gint layer;
179 gint zorder;
180 gdouble alpha;
181
182 if (!xmlStrcmp (element->name, ACCESSIBLE_NODE))
183 type = MY_TYPE_ATK_OBJECT;
184
185 if (!xmlStrcmp (element->name, ACC_ACTION_NODE))
186 type = MY_TYPE_ATK_ACTION;
187
188 if (!xmlStrcmp (element->name, ACC_COMPONENT_NODE))
189 type = MY_TYPE_ATK_COMPONENT;
190
191 if (!xmlStrcmp (element->name, ACC_DOCUMENT_NODE))
192 type = MY_TYPE_ATK_DOCUMENT;
193
194 if (!xmlStrcmp (element->name, ACC_EDIT_TEXT_NODE))
195 type = MY_TYPE_ATK_EDITABLE_TEXT;
196
197 if (!xmlStrcmp (element->name, ACC_HYPERLINK_NODE))
198 type = MY_TYPE_ATK_HYPERTEXT;
199
200 if (!xmlStrcmp (element->name, ACC_HYPERTEXT_NODE))
201 type = MY_TYPE_ATK_HYPERTEXT;
202
203 if (!xmlStrcmp (element->name, ACC_IMAGE_NODE))
204 type = MY_TYPE_ATK_IMAGE;
205
206 if (!xmlStrcmp (element->name, ACC_SELECTION_NODE))
207 type = MY_TYPE_ATK_SELECTION;
208
209 if (!xmlStrcmp (element->name, ACC_TEXT_NODE))
210 type = MY_TYPE_ATK_TEXT;
211
212 if (!xmlStrcmp (element->name, ACC_TABLE_NODE))
213 type = MY_TYPE_ATK_TABLE;
214
215 if (!xmlStrcmp (element->name, ACC_TABLE_CELL_NODE))
216 type = MY_TYPE_ATK_TABLE_CELL;
217
218 if (!xmlStrcmp (element->name, ACC_VALUE_NODE))
219 type = MY_TYPE_ATK_VALUE;
220
221
222 obj = g_object_new (type,
223 "accessible-name", name,
224 "accessible-description", description,
225 "accessible-role", atk_role_for_name ((const gchar *)role),
226 NULL);
227 child_node = element->xmlChildrenNode;
228 while (child_node != NULL) {
229 if (!xmlStrcmp (child_node->name, ACCESSIBLE_NODE) ||
230 !xmlStrcmp (child_node->name, ACC_ACTION_NODE) ||
231 !xmlStrcmp (child_node->name, ACC_COMPONENT_NODE) ||
232 !xmlStrcmp (child_node->name, ACC_DOCUMENT_NODE) ||
233 !xmlStrcmp (child_node->name, ACC_EDIT_TEXT_NODE) ||
234 !xmlStrcmp (child_node->name, ACC_HYPERLINK_NODE) ||
235 !xmlStrcmp (child_node->name, ACC_HYPERTEXT_NODE) ||
236 !xmlStrcmp (child_node->name, ACC_IMAGE_NODE) ||
237 !xmlStrcmp (child_node->name, ACC_SELECTION_NODE) ||
238 !xmlStrcmp (child_node->name, ACC_TABLE_NODE) ||
239 !xmlStrcmp (child_node->name, ACC_TABLE_CELL_NODE) ||
240 !xmlStrcmp (child_node->name, ACC_TEXT_NODE) ||
241 !xmlStrcmp (child_node->name, ACC_VALUE_NODE)) {
242 child_obj = create_atk_object_from_element (child_node);
243 my_atk_object_add_child (obj, child_obj);
244 }
245 child_node2 = child_node->xmlChildrenNode;
246 while (child_node2 != NULL) {
247 if (!xmlStrcmp (child_node2->name, RELATION_NODE)) {
248 relation_type = atoi_get_prop (child_node2, RELATION_TYPE_ATTR);
249 relation_target_name = xmlGetProp (child_node2, RELATION_TARGET_NAME_ATTR);
250 relation_set = atk_object_ref_relation_set (ATK_OBJECT (child_obj));
251 array[0] = ATK_OBJECT (obj);
252 relation = atk_relation_new (array, 1, relation_type);
253 atk_relation_new (array, 1, relation_type);
254 atk_relation_set_add (relation_set, relation);
255 g_object_unref (relation);
256 g_object_unref (relation_set);
257 xmlFree (relation_target_name);
258 }
259 if (!xmlStrcmp (child_node2->name, STATE_NODE)) {
260 state_set = atk_object_ref_state_set (ATK_OBJECT (child_obj));
261 state_enum = xmlGetProp (child_node2, STATE_TYPE_ATTR);
262 state_type = atk_state_type_for_name ((const gchar *)state_enum);
263 atk_state_set_add_state (state_set, state_type);
264 g_object_unref (state_set);
265 xmlFree (state_enum);
266 }
267 if (!xmlStrcmp (child_node2->name, ACTION_NODE)) {
268 action_name = xmlGetProp (child_node2, ACTION_NAME_ATTR);
269 action_des = xmlGetProp (child_node2, ACTION_DES_ATTR);
270 action_key_bind = xmlGetProp (child_node2, ACTION_KEY_BIND_ATTR);
271 my_atk_action_add_action (child_obj, (const gchar *)action_name,
272 (const gchar *)action_des,
273 (const gchar *)action_key_bind);
274 }
275 if (!xmlStrcmp (child_node2->name, COMPONENT_NODE)) {
276 x_extent = atoi_get_prop (child_node2, COMP_X_ATTR);
277 y_extent = atoi_get_prop (child_node2, COMP_Y_ATTR);
278 w_extent = atoi_get_prop (child_node2, COMP_WIDTH_ATTR);
279 h_extent = atoi_get_prop (child_node2, COMP_HEIGHT_ATTR);
280 layer = atoi_get_prop (child_node2, COMP_LAYER_ATTR);
281 zorder = atoi_get_prop (child_node2, COMP_ZORDER_ATTR);
282 alpha = atof_get_prop (child_node2, COMP_ALPHA_ATTR);
283 atk_component_set_extents (ATK_COMPONENT (child_obj),
284 x_extent,
285 y_extent,
286 w_extent,
287 h_extent,
288 ATK_XY_SCREEN);
289 my_atk_component_set_layer (ATK_COMPONENT (child_obj), layer);
290 my_atk_component_set_mdi_zorder (ATK_COMPONENT (child_obj), zorder);
291 my_atk_component_set_alpha (ATK_COMPONENT (child_obj), alpha);
292 }
293 if (!xmlStrcmp (child_node2->name, DOCUMENT_NODE)) {
294 my_atk_set_document (ATK_DOCUMENT(child_obj),
295 atoi_get_prop (child_node2, PAGE_ATTR),
296 atoi_get_prop (child_node2, PAGE_NUM_ATTR));
297 }
298 if (!xmlStrcmp (child_node2->name, HYPERLINK_NODE)) {
299 xmlChar *text = xmlGetProp (child_node2, TEXT_TEXT_ATTR);
300
301 my_atk_set_hypertext (ATK_HYPERTEXT (child_obj), (const gchar *)text);
302 xmlFree (text);
303 }
304 if (!xmlStrcmp (child_node2->name, HYPERTEXT_NODE)) {
305 xmlChar *text = xmlGetProp (child_node2, TEXT_TEXT_ATTR);
306
307 my_atk_set_hypertext (ATK_HYPERTEXT (child_obj), (const gchar *)text);
308 xmlFree (text);
309 }
310 if (!xmlStrcmp (child_node2->name, IMAGE_NODE)) {
311 image_des = xmlGetProp (child_node2, IMAGE_DES_ATTR);
312 x_size = atoi_get_prop (child_node2, COMP_X_ATTR);
313 y_size = atoi_get_prop (child_node2, COMP_Y_ATTR);
314 width = atoi_get_prop (child_node2, COMP_WIDTH_ATTR);
315 height = atoi_get_prop (child_node2, COMP_HEIGHT_ATTR);
316 image_locale = xmlGetProp (child_node2, IMAGE_LOCALE_ATTR);
317
318 my_atk_set_image (ATK_IMAGE (child_obj),
319 (const gchar *)image_des,
320 x_size,
321 y_size,
322 width,
323 height,
324 (const gchar *)image_locale);
325 }
326 if (!xmlStrcmp (child_node2->name, TEXT_NODE)) {
327 text = xmlGetProp (child_node2, TEXT_TEXT_ATTR);
328 AtkAttributeSet *attrSet = NULL;
329 AtkAttribute *a1 = get_atk_attribute (child_node2, TEXT_BOLD_ATTR);
330 AtkAttribute *a2 = get_atk_attribute (child_node2, TEXT_UNDERLINE_ATTR);
331 AtkAttribute *a3 = get_atk_attribute (child_node2, TEXT_DUMMY_ATTR);
332 attrSet = g_slist_append(NULL, a1);
333 attrSet = g_slist_append(attrSet, a2);
334 attrSet = g_slist_append(attrSet, a3);
335 my_atk_set_text (ATK_TEXT (child_obj),
336 (const gchar *)text,
337 atoi_get_prop (child_node2, COMP_X_ATTR),
338 atoi_get_prop (child_node2, COMP_Y_ATTR),
339 atoi_get_prop (child_node2, COMP_WIDTH_ATTR),
340 atoi_get_prop (child_node2, COMP_HEIGHT_ATTR),
341 attrSet);
342 }
343 if (!xmlStrcmp (child_node2->name, TABLE_CELL_NODE)) {
344 my_atk_set_table_cell (ATK_TABLE_CELL (child_obj),
345 atoi_get_prop (child_node2, CELL_X_ATTR),
346 atoi_get_prop (child_node2, CELL_Y_ATTR),
347 atoi_get_prop (child_node2, ROW_SPAN_ATTR),
348 atoi_get_prop (child_node2, COLUMN_SPAN_ATTR));
349 }
350 if (!xmlStrcmp (child_node2->name, VALUE_NODE)) {
351 my_atk_set_value (ATK_VALUE(child_obj),
352 atof_get_prop (child_node2, MIN_ATTR),
353 atof_get_prop (child_node2, CURRENT_ATTR),
354 atof_get_prop (child_node2, MAX_ATTR),
355 atof_get_prop (child_node2, STEP_ATTR));
356 }
357 child_node2 = child_node2->next;
358 }
359 child_node = child_node->next;
360 }
361 return obj;
362 }
363
364 /*
365 * Reads the XML from filename and uses it
366 * to create a tree of MyAtkObjects.
367 *
368 * returns: The root object of the tree.
369 */
370 MyAtkObject *
atk_object_xml_parse(gchar * filename)371 atk_object_xml_parse (gchar *filename)
372 {
373 xmlDoc *doc;
374 xmlNode *root_element;
375 MyAtkObject *new_atk_object = NULL;
376
377 doc = xmlReadFile (filename, NULL, 0);
378 g_assert (doc != NULL);
379
380 root_element = xmlDocGetRootElement (doc);
381
382 if (!root_element)
383 return NULL;
384
385 new_atk_object = create_atk_object_from_element (root_element);
386
387 xmlFreeDoc (doc);
388 return new_atk_object;
389 }
390