2 * AT-SPI - Assistive Technology Service Provider Interface
3 * (Gnome Accessibility Project; https://wiki.gnome.org/Accessibility)
5 * Copyright (c) 2015 Samsung Electronics Co., Ltd.
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
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 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 * Boston, MA 02111-1307, USA.
28 #include "my-atk-object.h"
29 #include "my-atk-text.h"
31 typedef struct _MyAtkTextInfo MyAtkTextInfo;
33 static void atk_text_interface_init (AtkTextIface *iface);
35 typedef struct _MyAtkTextSelection MyAtkTextSelection;
37 struct _MyAtkTextSelection {
42 G_DEFINE_TYPE_WITH_CODE (MyAtkText,
45 G_IMPLEMENT_INTERFACE (ATK_TYPE_TEXT,
46 atk_text_interface_init));
49 my_atk_set_text (AtkText *obj,
55 AtkAttributeSet *attrSet)
57 g_return_val_if_fail (MY_IS_ATK_TEXT (obj), -1);
59 MyAtkText *self = MY_ATK_TEXT (obj);
60 self->text = g_strdup (text);
64 self->height = height;
65 self->attributes = g_slist_copy (attrSet);
71 my_atk_text_new (void)
73 return g_object_new (MY_TYPE_ATK_TEXT, NULL);
77 my_atk_text_get_text (AtkText *obj, gint start_offset, gint end_offset)
79 g_return_val_if_fail (MY_IS_ATK_TEXT (obj), NULL);
80 gchar *str = MY_ATK_TEXT (obj)->text;
82 if ((end_offset < start_offset) || start_offset < 0 || !str)
84 if (strlen (str) < end_offset)
87 return g_strndup (str + start_offset, end_offset - start_offset);
91 my_atk_text_get_character_count (AtkText *obj)
93 g_return_val_if_fail (MY_IS_ATK_TEXT (obj), -1);
94 gchar *str = MY_ATK_TEXT (obj)->text;
96 return (gint) strlen (str);
100 my_atk_text_get_caret_offset (AtkText *obj)
102 g_return_val_if_fail (MY_IS_ATK_TEXT (obj), -1);
103 return MY_ATK_TEXT (obj)->caret_offset;
107 my_atk_text_set_caret_offset (AtkText *obj, gint offset)
109 g_return_val_if_fail (MY_IS_ATK_TEXT (obj), FALSE);
110 MyAtkText *self = MY_ATK_TEXT (obj);
111 if (offset < 0 && strlen (self->text) <= offset)
113 self->caret_offset = offset;
118 my_atk_text_get_character_at_offset (AtkText *obj, gint offset)
120 g_return_val_if_fail (MY_IS_ATK_TEXT (obj), 255);
121 return MY_ATK_TEXT (obj)->text[offset];
125 my_atk_text_get_character_extents (AtkText *obj, gint offset, gint *x, gint *y, gint *width, gint *height, AtkCoordType coords)
127 g_return_if_fail (MY_IS_ATK_TEXT (obj));
128 MyAtkText *self = MY_ATK_TEXT (obj);
131 *width = self->width;
132 *height = self->height;
136 my_atk_text_get_range_extents (AtkText *obj, gint start_offset, gint stop_offset, AtkCoordType coords, AtkTextRectangle *rect)
138 g_return_if_fail (MY_IS_ATK_TEXT (obj));
139 MyAtkText *self = MY_ATK_TEXT (obj);
142 rect->width = self->width;
143 rect->height = self->height;
147 my_atk_text_get_n_selections (AtkText *obj)
149 g_return_val_if_fail (MY_IS_ATK_TEXT (obj), -1);
150 return g_list_length (MY_ATK_TEXT (obj)->selection);
154 my_atk_text_add_selection (AtkText *obj, gint start_offset, gint end_offset)
156 MyAtkText *self = MY_ATK_TEXT (obj);
157 g_return_val_if_fail (MY_IS_ATK_TEXT (obj), FALSE);
159 MyAtkTextSelection *node = g_malloc (sizeof (MyAtkTextSelection));
161 node->start = start_offset;
162 node->end = end_offset;
164 self->selection = g_list_append (self->selection, node);
170 my_atk_text_get_selection (AtkText *obj, gint selection_num, gint *start_offset, gint *end_offset)
172 MyAtkText *self = MY_ATK_TEXT (obj);
175 g_return_val_if_fail (MY_IS_ATK_TEXT (obj), NULL);
177 if (selection_num < 0)
180 it = g_list_nth (self->selection, selection_num);
184 str = my_atk_text_get_text (obj, ((MyAtkTextSelection *)it->data)->start, ((MyAtkTextSelection *)it->data)->end);
187 *start_offset = ((MyAtkTextSelection *)it->data)->start;
188 *end_offset = ((MyAtkTextSelection *)it->data)->end;
194 my_atk_text_set_selection (AtkText *obj, gint selection_num, gint start_offset, gint end_offset)
196 MyAtkText *self = MY_ATK_TEXT (obj);
197 g_return_val_if_fail (MY_IS_ATK_TEXT (obj), FALSE);
201 if (selection_num < 0)
204 it = g_list_nth (self->selection, selection_num);
208 ((MyAtkTextSelection *)it->data)->start = start_offset;
209 ((MyAtkTextSelection *)it->data)->end = end_offset;
215 my_atk_text_remove_selection (AtkText *obj, gint selection_num)
217 MyAtkText *self = MY_ATK_TEXT (obj);
219 g_return_val_if_fail (MY_IS_ATK_TEXT (obj), FALSE);
221 if (selection_num < 0)
224 it = g_list_nth (self->selection, selection_num);
228 self->selection = g_list_delete_link (self->selection, it);
233 my_atk_text_get_offset_at_point (AtkText *obj, gint x, gint y, AtkCoordType coords)
235 g_return_val_if_fail (MY_IS_ATK_TEXT (obj), -1);
239 static AtkAttributeSet *
240 my_atk_text_get_default_attributes (AtkText *obj)
242 g_return_val_if_fail (MY_IS_ATK_TEXT (obj), NULL);
243 return MY_ATK_TEXT (obj)->attributes;
246 static AtkAttributeSet *
247 my_atk_text_get_run_attributes (AtkText *obj, gint offset, gint *start_offset, gint *end_offset)
249 g_return_val_if_fail (MY_IS_ATK_TEXT (obj), NULL);
250 AtkAttributeSet *attributes;
253 attr = g_malloc (sizeof (AtkAttribute));
254 attr->name = g_strdup ("text_test_attr1");
255 attr->value = g_strdup ("on");
256 attributes = g_slist_append (NULL, attr);
258 attr = g_malloc (sizeof (AtkAttribute));
259 attr->name = g_strdup ("text_test_attr2");
260 attr->value = g_strdup ("off");
261 attributes = g_slist_append (attributes, attr);
269 static void setSentenceStartEnd (MyAtkText *self,gint *_offset, gint *start_offset, gint*end_offset, const gchar *fstr)
271 gchar *p_str_begin = NULL;
272 gchar *p_str_end = NULL;
273 const gint length = strlen (self->text);
274 gint offset = *_offset;
275 gint star_correction = 1;
277 * In case if offset is in the middle of the word rewind to 1 character before.
279 for (; g_ascii_isalpha (self->text[offset]) && 0 < offset; offset--);
281 * if [char] rewind to word after by passing none alpha
282 * else try to find last [string] in range [0,offset]
283 * if found then correct position
284 * else not found so this is first sentence find first word
286 if (self->text[offset] == fstr[0]) {
287 for (; !g_ascii_isalpha (self->text[offset]) && offset < length; offset++);
288 p_str_begin = self->text + offset;
290 p_str_begin = g_strrstr_len (self->text, offset, fstr);
292 for (; !g_ascii_isalpha (self->text[offset]) && length < offset; offset++);
294 for (offset = 0; !g_ascii_isalpha (self->text[offset]) && length < offset; offset++);
297 p_str_begin = self->text + offset;
301 * if not found set ending at text end.
303 p_str_end = g_strstr_len (self->text + offset, length - offset, fstr);
305 p_str_end = self->text + (length -1);
307 if (p_str_begin && p_str_end) {
308 *start_offset = p_str_begin - self->text + star_correction;
309 *end_offset = p_str_end - self->text + 1;
315 my_atk_text_get_string_at_offset (AtkText *obj, gint offset, AtkTextGranularity granularity, gint *start_offset, gint *end_offset)
317 g_return_val_if_fail (MY_IS_ATK_TEXT (obj), NULL);
318 MyAtkText *self = MY_ATK_TEXT (obj);
325 switch (granularity) {
326 case ATK_TEXT_GRANULARITY_CHAR:
327 *start_offset = offset;
328 *end_offset = *start_offset + 1;
330 case ATK_TEXT_GRANULARITY_WORD:
331 length = strlen (self->text);
332 for (; !g_ascii_isalpha (self->text[offset]) && offset < length ; offset++);
333 for (cnt = offset; cnt < length; cnt++) {
334 if (!g_ascii_isalpha (self->text[cnt])) {
335 *start_offset = offset;
336 *end_offset = cnt - 1;
341 for (cnt = offset; 0 < cnt; cnt--) {
342 if (!g_ascii_isalpha (self->text[cnt])) {
343 *start_offset = cnt + 1;
348 case ATK_TEXT_GRANULARITY_SENTENCE:
349 setSentenceStartEnd (self, &offset, start_offset, end_offset, ".");
351 case ATK_TEXT_GRANULARITY_LINE:
352 setSentenceStartEnd (self, &offset, start_offset, end_offset, "/n");
354 case ATK_TEXT_GRANULARITY_PARAGRAPH:
355 /* Not implemented */
362 return my_atk_text_get_text (obj, *start_offset, *end_offset + myoffset);
366 my_atk_get_bounded_ranges (AtkText *obj, AtkTextRectangle *rect, AtkCoordType ctype, AtkTextClipType xclip, AtkTextClipType yclip)
368 g_return_val_if_fail (MY_IS_ATK_TEXT (obj), NULL);
369 AtkTextRange **range = g_new (AtkTextRange *, 3);
371 *range = g_new (AtkTextRange, 1);
372 (*range)->start_offset = 0;
373 (*range)->end_offset = 5;
374 (*range)->content = my_atk_text_get_text (obj, (*range)->start_offset, (*range)->end_offset);
376 *(range+1) = g_new (AtkTextRange, 1);
377 (*(range+1))->start_offset = 6;
378 (*(range+1))->end_offset = 10;
379 (*(range+1))->content = my_atk_text_get_text (obj, (*(range+1))->start_offset, (*(range+1))->end_offset);
387 atk_text_interface_init (AtkTextIface *iface)
391 iface->get_text = my_atk_text_get_text;
392 iface->get_character_count = my_atk_text_get_character_count;
393 iface->get_caret_offset = my_atk_text_get_caret_offset;
394 iface->set_caret_offset = my_atk_text_set_caret_offset;
395 iface->get_character_at_offset = my_atk_text_get_character_at_offset;
396 iface->get_character_extents = my_atk_text_get_character_extents;
397 iface->get_range_extents = my_atk_text_get_range_extents;
398 iface->get_n_selections = my_atk_text_get_n_selections;
399 iface->add_selection = my_atk_text_add_selection;
400 iface->get_selection = my_atk_text_get_selection;
401 iface->set_selection = my_atk_text_set_selection;
402 iface->remove_selection = my_atk_text_remove_selection;
403 iface->get_offset_at_point = my_atk_text_get_offset_at_point;
404 iface->get_default_attributes = my_atk_text_get_default_attributes;
405 iface->get_string_at_offset = my_atk_text_get_string_at_offset;
406 iface->get_bounded_ranges = my_atk_get_bounded_ranges;
407 iface->get_run_attributes = my_atk_text_get_run_attributes;
411 my_atk_text_init (MyAtkText *self)
414 self->caret_offset = -1;
419 self->selection = NULL;
420 self->attributes = NULL;
424 my_atk_text_class_initialize (AtkObject *obj, gpointer data)
429 my_atk_text_class_finalize (GObject *obj)
434 my_atk_text_class_init (MyAtkTextClass *my_class)
436 AtkObjectClass *atk_class = ATK_OBJECT_CLASS (my_class);
437 GObjectClass *gobject_class = G_OBJECT_CLASS (my_class);
439 gobject_class->finalize = my_atk_text_class_finalize;
440 atk_class->initialize = my_atk_text_class_initialize;