Fix get_text_after/at/before_offset for elm_entry and elm_label.
authorKarol Furmaniak <k.furmaniak@samsung.com>
Tue, 19 Nov 2013 11:19:25 +0000 (12:19 +0100)
committerKarol Furmaniak <k.furmaniak@samsung.com>
Tue, 19 Nov 2013 11:19:25 +0000 (12:19 +0100)
eail/eail/eail_entry.c
eail/eail/eail_label.c
eail/eail/eail_utils.c
eail/eail/eail_utils.h

index d5af011..74e36b7 100644 (file)
@@ -421,760 +421,6 @@ eail_entry_get_text(AtkText   *text,
 }
 
 
-
-/**
- * @brief Returns the position that is obtained by adding count to the
- * given offset
- *
- * Count may be positive or negative.
- *
- * @param textblock Evas textblock
- * @param offset character offset
- * @param count number of characters to move from offset
- * @returns integer representing the new position
- */
-static gint
-_eail_move_chars(const Evas_Object *textblock,
-                 gint offset,
-                 gint count)
-{
-   Evas_Textblock_Cursor *cur;
-   gint dir;
-   gboolean res;
-
-   dir = count > 0 ? 1 : -1;
-   cur = evas_object_textblock_cursor_new(textblock);
-   evas_textblock_cursor_pos_set(cur, offset);
-
-   while(count)
-     {
-        res = dir > 0 ? evas_textblock_cursor_char_next(cur) :
-            evas_textblock_cursor_char_prev(cur);
-        if (!res) break;
-
-        count -= dir;
-     }
-
-   offset = evas_textblock_cursor_pos_get(cur);
-   evas_textblock_cursor_free(cur);
-
-   return offset;
-}
-
-/**
- * @brief Gets the utf8 character at offset
- *
- * @param textblock Evas textblock
- * @param offset character offset
- * @returns char representing the utf8 character
- */
-static gunichar
-_eail_get_unichar_at_offset(const Evas_Object *textblock,
-                            int offset)
-{
-   Evas_Textblock_Cursor *cur;
-   gchar *s;
-   gunichar c;
-
-   cur = evas_object_textblock_cursor_new(textblock);
-   evas_textblock_cursor_pos_set(cur, offset);
-   s = evas_textblock_cursor_content_get(cur);
-   c = g_utf8_get_char(s);
-
-   evas_textblock_cursor_free(cur);
-   g_free(s);
-
-   return c;
-}
-
-/**
- * @brief Checks whether the character at offset in textblock is a word's start
- *
- * @param textblock Evas textblock
- * @param offset character offset
- * @returns TRUE on success, FALSE otherwise
- */
-static gboolean
-_eail_is_word_start(const Evas_Object *textblock,
-                    gint offset)
-{
-   /* first character in a word */
-   gunichar c1, c2;
-
-   c1 = _eail_get_unichar_at_offset(textblock, offset);
-   c2 = _eail_get_unichar_at_offset(textblock, offset - 1);
-   if (g_unichar_isalnum(c1) && g_unichar_isspace(c2)) return TRUE;
-
-   return FALSE;
-}
-
-/**
- * @brief Checks whether the character at offset in textblock is a word's end
- *
- * @param textblock Evas textblock
- * @param offset character offset
- * @return TRUE on success, FALSE otherwise
- */
-static gboolean
-_eail_is_word_end(const Evas_Object *textblock,
-                  gint offset)
-{
-   /* is first non-word char after a word */
-   gunichar c1, c2;
-
-   c1 = _eail_get_unichar_at_offset(textblock, offset - 1);
-   c2 = _eail_get_unichar_at_offset(textblock, offset);
-   if (g_unichar_isalnum(c1) && g_unichar_isspace(c2)) return TRUE;
-
-   return FALSE;
-}
-
-/**
- * @brief Checks whether the character at offset in textblock is inside a word
- *
- * @param textblock Evas textblock
- * @param offset character offset
- * @returns TRUE on success, FALSE otherwise
- */
-static gboolean
-_eail_is_inside_word(const Evas_Object *textblock,
-                     gint offset)
-{
-   gunichar c1, c2, c3;
-
-   c1 = _eail_get_unichar_at_offset(textblock, offset - 1);
-   c2 = _eail_get_unichar_at_offset(textblock, offset);
-   c3 = _eail_get_unichar_at_offset(textblock, offset + 1);
-   if (g_unichar_isalnum(c1) && g_unichar_isalnum(c2) && g_unichar_isalnum(c3))
-     return TRUE;
-
-   if (g_unichar_isalnum(c1) && g_unichar_isalnum(c2) && g_unichar_isspace(c3))
-     return TRUE;
-
-   if (g_unichar_isspace(c1) && g_unichar_isalnum(c2) && g_unichar_isalnum(c3))
-     return TRUE;
-
-   if (g_unichar_isspace(c1) && g_unichar_isalnum(c2) && g_unichar_isspace(c3))
-     return TRUE;
-
-   return FALSE;
-}
-
-/**
- * @brief Gets the texblock length
- *
- * @param textblock Evas textblock
- * @returns integer representing the textblock length
- */
-static gint
-_eail_get_len(const Evas_Object *textblock)
-{
-   Evas_Textblock_Cursor *cur;
-   int ctr = 0;
-
-   cur = evas_object_textblock_cursor_new(textblock);
-   while (evas_textblock_cursor_char_next(cur))
-     ++ctr;
-
-   evas_textblock_cursor_free(cur);
-
-   return ctr;
-}
-
-/**
- * @brief Returns the position that is count words from the given offset
- *
- * Count may  be positive or negative. If count is positive, the returned
- * position will be a word end, otherwise it will be a word start.
- *
- * @param textblock Evas textblock
- * @param offset a character offset
- * @param count the number of words to move from offset
- * @returns integer representing the new position
- */
-static gint
-_eail_move_words(const Evas_Object *textblock,
-                 gint offset,
-                 gint count)
-{
-   gint len = _eail_get_len(textblock);
-
-   while (count > 0 && offset < len)
-     {
-        do
-          offset++;
-        while (offset < len && !_eail_is_word_end(textblock, offset));
-
-        count--;
-     }
-   while (count < 0 && offset > 0)
-     {
-        do
-          offset--;
-        while (offset > 0 && !_eail_is_word_start(textblock, offset));
-
-        count++;
-     }
-
-   return offset;
-}
-
-/**
- * @brief Gets the position of the first character in line
- *
- * @param cur Evas_Textblock_Cursor instance
- * @returns TRUE on success, FALSE otherwise
- */
-static gint
-_eail_get_line_start(Evas_Textblock_Cursor *cur)
-{
-   gint start = 0;
-   gint pos;
-
-   pos = evas_textblock_cursor_pos_get(cur);
-   evas_textblock_cursor_line_char_first(cur);
-   start = evas_textblock_cursor_pos_get(cur);
-   evas_textblock_cursor_pos_set(cur, pos);
-
-   return start;
-}
-
-/**
- * @brief Gets the position of the last character in line
- *
- * @param cur Evas_Textblock_Cursor instance
- * @returns TRUE on success, FALSE otherwise
- */
-static gint
-_eail_get_line_end(Evas_Textblock_Cursor *cur)
-{
-   gint end = 0;
-   gint pos;
-
-   pos = evas_textblock_cursor_pos_get(cur);
-   evas_textblock_cursor_line_char_last(cur);
-   end = evas_textblock_cursor_pos_get(cur);
-   evas_textblock_cursor_pos_set(cur, pos);
-
-   return end;
-}
-
-/**
- * @brief Moves the cursor to the beginning of the next line
- *
- * @param cur Evas_Textblock_Cursor instance
- * @returns TRUE on success, FALSE otherwise
- */
-static gboolean
-_eail_iter_next_line(Evas_Textblock_Cursor *cur)
-{
-   evas_textblock_cursor_line_char_last(cur);
-
-   return evas_textblock_cursor_char_next(cur);
-}
-
-/**
- * @brief Gets the length of the line shown by cursor cur
- *
- * @param cur Evas_Textblock_Cursor instance
- * @return integer representing the length of the line
- */
-static gint
-_eail_get_line_length(Evas_Textblock_Cursor *cur)
-{
-   gint start;
-   gint end;
-
-   start = _eail_get_line_start(cur);
-   end = _eail_get_line_end(cur);
-
-   return end - start + 1;
-}
-
-/**
- * @brief Gets the line before offset
- *
- * @param entry Evas_Object instance
- * @param boundary_type AtkTextBoundary instance
- * @param offset character offset
- * @param [out] start_offset start offset of the returned string
- * @param [out] end_offset offset of the first character after the
- * returned substring
- */
-static void
-_eail_get_line_before(Evas_Object     *entry,
-                      AtkTextBoundary  boundary_type,
-                      gint             offset,
-                      gint            *start_offset,
-                      gint            *end_offset)
-{
-   Evas_Object *textblock;
-   Evas_Textblock_Cursor *cur, *prev_cur = NULL, *prev_prev_cur = NULL;
-   gint index, start_index, end_index;
-   const gchar *text;
-   gboolean found = FALSE;
-
-   textblock = elm_entry_textblock_get(entry);
-   cur = evas_object_textblock_cursor_new(textblock);
-
-   text = evas_textblock_text_markup_to_utf8(
-       textblock, evas_object_textblock_text_markup_get(textblock));
-   index = g_utf8_offset_to_pointer (text, offset) - text;
-   do
-     {
-        start_index = _eail_get_line_start(cur);
-        end_index = start_index + _eail_get_line_length(cur);
-
-        if (index >= start_index && index <= end_index)
-          {
-             /* Found line for offset */
-             if (prev_cur)
-               {
-                  switch (boundary_type)
-                    {
-                      case ATK_TEXT_BOUNDARY_LINE_START:
-                          end_index = start_index;
-                          start_index = _eail_get_line_start(prev_cur);
-                          break;
-                      case ATK_TEXT_BOUNDARY_LINE_END:
-                          if (prev_prev_cur)
-                            start_index = _eail_get_line_start(prev_prev_cur) +
-                                _eail_get_line_length(prev_prev_cur);
-                          else
-                            start_index = 0;
-                          end_index = _eail_get_line_start(prev_cur) +
-                              _eail_get_line_length(prev_cur);
-                          break;
-                      default:
-                          g_assert_not_reached();
-                    }
-               }
-             else
-               start_index = end_index = 0;
-
-             found = TRUE;
-             break;
-          }
-
-        prev_prev_cur = prev_cur;
-        prev_cur = cur;
-     }
-   while (_eail_iter_next_line(cur));
-
-   if (!found)
-     {
-        start_index = _eail_get_line_start(prev_cur) +
-            _eail_get_line_length(prev_cur);
-        end_index = start_index;
-     }
-   evas_textblock_cursor_free(cur);
-
-   *start_offset = g_utf8_pointer_to_offset(text, text + start_index);
-   *end_offset = g_utf8_pointer_to_offset(text, text + end_index);
-}
-
-/**
- * @brief Gets the line after offset
- *
- * @param entry Evas_Object instance
- * @param boundary_type AtkTextBoundary instance
- * @param offset character offset
- * @param [out] start_offset start offset of the returned string
- * @param [out] end_offset offset of the first character after the
- * returned substring
- */
-static void
-_eail_get_line_after (Evas_Object     *entry,
-                      AtkTextBoundary  boundary_type,
-                      gint             offset,
-                      gint            *start_offset,
-                      gint            *end_offset)
-{
-   Evas_Object *textblock;
-   Evas_Textblock_Cursor *cur, *prev_cur = NULL;
-   gint index, start_index, end_index;
-   const gchar *text;
-   gboolean found = FALSE;
-
-   textblock = elm_entry_textblock_get(entry);
-   cur = evas_object_textblock_cursor_new(textblock);
-   text = evas_textblock_text_markup_to_utf8(
-       textblock, evas_object_textblock_text_markup_get(textblock));
-
-   index = g_utf8_offset_to_pointer (text, offset) - text;
-   do
-     {
-        start_index = _eail_get_line_start(cur);
-        end_index = start_index + _eail_get_line_length(cur);
-
-        if (index >= start_index && index <= end_index)
-          {
-             /* Found line for offset */
-             if (_eail_iter_next_line (cur))
-               {
-                  switch (boundary_type)
-                    {
-                      case ATK_TEXT_BOUNDARY_LINE_START:
-                          start_index = _eail_get_line_start(cur);
-                          if (_eail_iter_next_line (cur))
-                            end_index = _eail_get_line_start(cur);
-                          else
-                            end_index = start_index + _eail_get_line_length(cur);
-                          break;
-                      case ATK_TEXT_BOUNDARY_LINE_END:
-                          start_index = end_index;
-                          end_index = _eail_get_line_start(cur) +
-                              _eail_get_line_length(cur);
-                          break;
-                      default:
-                          g_assert_not_reached();
-                    }
-               }
-             else
-               start_index = end_index;
-
-             found = TRUE;
-             break;
-          }
-
-        prev_cur = cur;
-     }
-   while (_eail_iter_next_line (cur));
-
-   if (!found)
-     {
-        start_index = _eail_get_line_start(prev_cur) +
-            _eail_get_line_length(prev_cur);
-        end_index = start_index;
-     }
-   evas_textblock_cursor_free(cur);
-
-   *start_offset = g_utf8_pointer_to_offset (text, text + start_index);
-   *end_offset = g_utf8_pointer_to_offset (text, text + end_index);
-}
-
-/**
- * @brief Gets the line at offset
- *
- * @param entry Evas_Object instance
- * @param boundary_type AtkTextBoundary instance
- * @param offset character offset
- * @param [out] start_offset start offset of the returned string
- * @param [out] end_offset offset of the first character after the
- * returned substring
- */
-static void
-_eail_get_line_at (Evas_Object *entry,
-                   AtkTextBoundary  boundary_type,
-                   gint             offset,
-                   gint            *start_offset,
-                   gint            *end_offset)
-{
-   Evas_Object *textblock;
-   Evas_Textblock_Cursor *cur, *prev_cur = NULL;
-   gint index, start_index, end_index;
-   const gchar *text;
-   gboolean found = FALSE;
-
-   textblock = elm_entry_textblock_get(entry);
-   cur = evas_object_textblock_cursor_new(textblock);
-
-   text = evas_textblock_text_markup_to_utf8(
-       textblock, evas_object_textblock_text_markup_get(textblock));
-   index = g_utf8_offset_to_pointer (text, offset) - text;
-   do
-     {
-        start_index = _eail_get_line_start(cur);
-        end_index = start_index + _eail_get_line_end(cur);
-
-        if (index >= start_index && index <= end_index)
-          {
-             /* Found line for offset */
-             switch (boundary_type)
-               {
-                 case ATK_TEXT_BOUNDARY_LINE_START:
-                     if (_eail_iter_next_line (cur))
-                       end_index = _eail_get_line_start(cur);
-                     break;
-                 case ATK_TEXT_BOUNDARY_LINE_END:
-                     if (prev_cur)
-                       start_index = _eail_get_line_start(prev_cur) +
-                           _eail_get_line_length(prev_cur);
-                     break;
-                 default:
-                     g_assert_not_reached();
-               }
-
-             found = TRUE;
-             break;
-          }
-
-        prev_cur = cur;
-     }
-   while (_eail_iter_next_line (cur));
-
-   if (!found)
-     {
-        start_index = _eail_get_line_start(prev_cur) +
-            _eail_get_line_length(prev_cur);
-        end_index = start_index;
-     }
-   evas_textblock_cursor_free(cur);
-
-   *start_offset = g_utf8_pointer_to_offset (text, text + start_index);
-   *end_offset = g_utf8_pointer_to_offset (text, text + end_index);
-}
-
-/**
- * @brief Gets a slice of the text from entry after offset
- *
- * Use g_free() to free the returned string.
- *
- * @param entry entry widget
- * @param offset character offset
- * @param boundary_type AtkTextBoundary instance
- * @param [out] start_offset start position of the returned text
- * @param [out] end_offset end position of the returned text
- * @returns newly allocated string containg a slice of text from textblock
- */
-static gchar *
-_eail_get_text_after(Evas_Object *entry,
-                     gint offset,
-                     AtkTextBoundary boundary_type,
-                     gint *start_offset,
-                     gint *end_offset)
-{
-   const gchar *text;
-   int len;
-   gint start, end;
-   Evas_Object *textblock;
-
-   if (!entry) return g_strdup("");
-
-   textblock = elm_entry_textblock_get(entry);
-
-   text = evas_textblock_text_markup_to_utf8(
-       textblock, evas_object_textblock_text_markup_get(textblock));
-   if (!text)
-     {
-        *start_offset = 0;
-        *end_offset = 0;
-        return g_strdup("");
-     }
-
-   start = offset;
-   end = offset;
-   len = _eail_get_len(textblock);
-
-   switch (boundary_type)
-     {
-       case ATK_TEXT_BOUNDARY_CHAR:
-           start = _eail_move_chars(textblock, start, 1);
-           end = start;
-           end = _eail_move_chars(textblock, end, 1);
-           break;
-
-       case ATK_TEXT_BOUNDARY_WORD_START:
-           if (_eail_is_inside_word(textblock, end))
-             end = _eail_move_words(textblock, end, 1);
-           while (!_eail_is_word_start(textblock, end) && end < len)
-             end = _eail_move_chars(textblock, end, 1);
-           start = end;
-           if (end < len)
-             {
-                end = _eail_move_words(textblock, end, 1);
-                while (!_eail_is_word_start(textblock, end) && end < len)
-                  end = _eail_move_chars(textblock, end, 1);
-             }
-           break;
-
-       case ATK_TEXT_BOUNDARY_WORD_END:
-           end = _eail_move_words(textblock, end, 1);
-           start = end;
-           if (end < len)
-             end = _eail_move_words(textblock, end, 1);
-           break;
-
-       case ATK_TEXT_BOUNDARY_SENTENCE_START:
-       case ATK_TEXT_BOUNDARY_SENTENCE_END:
-           break;
-
-       case ATK_TEXT_BOUNDARY_LINE_START:
-       case ATK_TEXT_BOUNDARY_LINE_END:
-           _eail_get_line_after (entry, boundary_type, offset, &start, &end);
-           break;
-     }
-
-   *start_offset = start;
-   *end_offset = end;
-   g_assert(start <= end);
-
-   return g_utf8_substring(text, start, end);
-}
-
-/**
- * @brief Gets a slice of the text from entry at offset
- *
- * Use g_free() to free the returned string.
- *
- * @param entry entry widget instance
- * @param offset character offset
- * @param boundary_type AtkTextBoundary instance
- * @param [out] start_offset start position of the returned text
- * @param [out] end_offset end position of the return text
- * @returns newly allocated string containing a slice of text from entry
- */
-static gchar *
-_eail_get_text_at(Evas_Object *entry,
-                  gint offset,
-                  AtkTextBoundary boundary_type,
-                  gint *start_offset,
-                  gint *end_offset)
-{
-   const gchar *text;
-   int len;
-   gint start, end;
-   Evas_Object *textblock;
-
-   if (!entry) return g_strdup("");
-
-   textblock = elm_entry_textblock_get(entry);
-
-   text = evas_textblock_text_markup_to_utf8(
-       textblock, evas_object_textblock_text_markup_get(textblock));
-   if (!text)
-     {
-        *start_offset = 0;
-        *end_offset = 0;
-        return g_strdup("");
-     }
-
-   start = offset;
-   end = offset;
-   len = _eail_get_len(textblock);
-
-   switch (boundary_type)
-     {
-       case ATK_TEXT_BOUNDARY_CHAR:
-           end = _eail_move_chars(textblock, end, 1);
-           break;
-
-       case ATK_TEXT_BOUNDARY_WORD_START:
-           if (!_eail_is_word_start(textblock, start))
-             start = _eail_move_words(textblock, start, -1);
-           if (_eail_is_inside_word(textblock, end))
-             end = _eail_move_words(textblock, end, 1);
-           while (!_eail_is_word_start(textblock, end) && end < len)
-             end = _eail_move_chars(textblock, end, 1);
-           break;
-
-       case ATK_TEXT_BOUNDARY_WORD_END:
-           if (_eail_is_inside_word(textblock, start) &&
-               !_eail_is_word_start(textblock, start))
-             start = _eail_move_words(textblock, start, -1);
-           while (!_eail_is_word_end(textblock, start) && start > 0)
-             start = _eail_move_chars(textblock, start, -1);
-           end = _eail_move_words(textblock, end, 1);
-           break;
-
-       case ATK_TEXT_BOUNDARY_SENTENCE_START:
-       case ATK_TEXT_BOUNDARY_SENTENCE_END:
-           break;
-
-       case ATK_TEXT_BOUNDARY_LINE_START:
-       case ATK_TEXT_BOUNDARY_LINE_END:
-           _eail_get_line_at (entry, boundary_type, offset, &start, &end);
-           break;
-     }
-
-   *start_offset = start;
-   *end_offset = end;
-   g_assert(start <= end);
-
-   return g_utf8_substring(text, start, end);
-}
-
-/**
- * @brief Gets a slice of the text from entry before offset
- *
- * Use g_free() to free the returned string.
- *
- * @param entry entry widget instance
- * @param offset character offset
- * @param boundary_type AtkTextBoundary instance
- * @param [out] start_offset start position of the returned text
- * @param [out] end_offset end position of the returned text
- * @returns newly allocated string containing a slice of text from entry
- */
-static gchar *
-_eail_get_text_before(Evas_Object *entry,
-                      gint offset,
-                      AtkTextBoundary boundary_type,
-                      gint *start_offset,
-                      gint *end_offset)
-{
-   const gchar *text;
-   gint start, end;
-   Evas_Object *textblock;
-
-   if (!entry) return g_strdup("");
-
-   textblock = elm_entry_textblock_get(entry);
-
-   text = evas_textblock_text_markup_to_utf8(
-       textblock, evas_object_textblock_text_markup_get(textblock));
-   if (!text)
-     {
-        *start_offset = 0;
-        *end_offset = 0;
-        return g_strdup("");
-     }
-
-   start = offset;
-   end = offset;
-
-   switch (boundary_type)
-     {
-       case ATK_TEXT_BOUNDARY_CHAR:
-           start = _eail_move_chars(textblock, start, -1);
-           break;
-
-       case ATK_TEXT_BOUNDARY_WORD_START:
-           if (!_eail_is_word_start(textblock, start))
-             start = _eail_move_words(textblock, start, -1);
-           end = start;
-           start = _eail_move_words(textblock, start, -1);
-           break;
-
-       case ATK_TEXT_BOUNDARY_WORD_END:
-           if (_eail_is_inside_word(textblock, start) &&
-               !_eail_is_word_start(textblock, start))
-             start = _eail_move_words(textblock, start, -1);
-           while (!_eail_is_word_end(textblock, start) && start > 0)
-             start = _eail_move_chars(textblock, start, -1);
-           end = start;
-           start = _eail_move_words(textblock, start, -1);
-           while (!_eail_is_word_end(textblock, start) && start > 0)
-             start = _eail_move_chars(textblock, start, -1);
-           break;
-
-       case ATK_TEXT_BOUNDARY_SENTENCE_START:
-       case ATK_TEXT_BOUNDARY_SENTENCE_END:
-           break;
-
-       case ATK_TEXT_BOUNDARY_LINE_START:
-       case ATK_TEXT_BOUNDARY_LINE_END:
-           _eail_get_line_before (entry, boundary_type, offset, &start, &end);
-           break;
-     }
-
-   *start_offset = start;
-   *end_offset = end;
-   g_assert(start <= end);
-
-   return g_utf8_substring(text, start, end);
-}
-
 /**
  * @brief Gets the specified text after offset
  *
@@ -1197,12 +443,15 @@ eail_entry_get_text_after_offset(AtkText *text,
                                  gint *end_offset)
 {
    Evas_Object *widget;
+   Evas_Object *textblock;
 
    widget = eail_widget_get_widget(EAIL_WIDGET(text));
    if (!widget) return NULL;
 
-   return _eail_get_text_after(widget, offset, boundary_type, start_offset,
-                               end_offset);
+   textblock = elm_entry_textblock_get(widget);
+
+   return eail_get_text_after(textblock, offset, boundary_type, start_offset,
+                              end_offset);
 
 }
 
@@ -1228,12 +477,15 @@ eail_entry_get_text_at_offset(AtkText *text,
                               gint *end_offset)
 {
    Evas_Object *widget;
+   Evas_Object *textblock;
 
    widget = eail_widget_get_widget(EAIL_WIDGET(text));
    if (!widget) return NULL;
 
-   return _eail_get_text_at(widget, offset, boundary_type, start_offset,
-                            end_offset);
+   textblock = elm_entry_textblock_get(widget);
+
+   return eail_get_text_at(textblock, offset, boundary_type, start_offset,
+                           end_offset);
 }
 
 /**
@@ -1258,12 +510,15 @@ eail_entry_get_text_before_offset(AtkText *text,
                                   gint *end_offset)
 {
    Evas_Object *widget;
+   Evas_Object *textblock;
 
    widget = eail_widget_get_widget(EAIL_WIDGET(text));
    if (!widget) return NULL;
 
-   return _eail_get_text_before(widget, offset, boundary_type, start_offset,
-                                end_offset);
+   textblock = elm_entry_textblock_get(widget);
+
+   return eail_get_text_before(textblock, offset, boundary_type, start_offset,
+                               end_offset);
 }
 
 /**
index 7a2f08c..d7a5885 100644 (file)
@@ -313,6 +313,113 @@ eail_label_get_run_attributes(AtkText *text,
 }
 
 /**
+ * @brief Gets the specified text after offset
+ *
+ * Use g_free() to free the returned string.
+ *
+ * @param text AtkText instance
+ * @param offset character offset
+ * @param boundary_type AtkTextBoundary instance
+ * @param [out] start_offset start offset of the returned string
+ * @param [out] end_offset offset of the first character after the returned
+ * substring
+ * @returns newly allocated string containing the text after offset bounded
+ * by the specified boundary_type
+ */
+static gchar *
+eail_label_get_text_after_offset(AtkText *text,
+                                 gint offset,
+                                 AtkTextBoundary boundary_type,
+                                 gint *start_offset,
+                                 gint *end_offset)
+{
+   Evas_Object *widget;
+   const Evas_Object *textblock;
+   Evas_Object *label_edje_layer;
+
+   widget = eail_widget_get_widget(EAIL_WIDGET(text));
+   if (!widget) return NULL;
+
+   label_edje_layer = elm_layout_edje_get(widget);
+   textblock = edje_object_part_object_get(label_edje_layer, "elm.text");
+
+   return eail_get_text_after(textblock, offset, boundary_type, start_offset,
+                              end_offset);
+
+}
+
+/**
+ * @brief Gets the specified text at offset
+ *
+ * Use g_free() to free the returned string.
+ *
+ * @param text AtkText instance
+ * @param offset character offset
+ * @param boundary_type AtkTextBoundary instance
+ * @param [out] start_offset start offset of the returned string
+ * @param [out] end_offset offset of the first character after the returned
+ * substring
+ * @returns newly allocated string containing the text after offset bounded
+ * by the specified boundary_type
+ */
+static gchar *
+eail_label_get_text_at_offset(AtkText *text,
+                              gint offset,
+                              AtkTextBoundary boundary_type,
+                              gint *start_offset,
+                              gint *end_offset)
+{
+   Evas_Object *widget;
+   const Evas_Object *textblock;
+   Evas_Object *label_edje_layer;
+
+   widget = eail_widget_get_widget(EAIL_WIDGET(text));
+   if (!widget) return NULL;
+
+   label_edje_layer = elm_layout_edje_get(widget);
+   textblock = edje_object_part_object_get(label_edje_layer, "elm.text");
+
+   return eail_get_text_at(textblock, offset, boundary_type, start_offset,
+                           end_offset);
+}
+
+/**
+ * @brief Gets the specified text before offset
+ *
+ * Use g_free() to free the returned string.
+ *
+ * @param text AtkText instance
+ * @param offset character offset
+ * @param boundary_type AtkTextBoundary instance
+ * @param [out] start_offset start offset of the returned string
+ * @param [out] end_offset offset of the first character after the returned
+ * substring
+ * @returns newly allocated string containing the text after offset bounded
+ * by the specified boundary_type
+ */
+static gchar *
+eail_label_get_text_before_offset(AtkText *text,
+                                  gint offset,
+                                  AtkTextBoundary boundary_type,
+                                  gint *start_offset,
+                                  gint *end_offset)
+{
+   Evas_Object *widget;
+   const Evas_Object *textblock;
+   Evas_Object *label_edje_layer;
+
+   widget = eail_widget_get_widget(EAIL_WIDGET(text));
+   if (!widget) return NULL;
+
+   label_edje_layer = elm_layout_edje_get(widget);
+   textblock = edje_object_part_object_get(label_edje_layer, "elm.text");
+
+   return eail_get_text_before(textblock, offset, boundary_type, start_offset,
+                               end_offset);
+}
+
+
+/**
  * @brief Initializes AtkTextIface interface
  *
  * @param iface AtkTextIface instance
@@ -325,5 +432,8 @@ atk_text_interface_init(AtkTextIface *iface)
    iface->get_text = eail_label_get_text;
    iface->get_run_attributes = eail_label_get_run_attributes;
    iface->get_default_attributes = eail_label_get_default_attributes;
+   iface->get_text_after_offset = eail_label_get_text_after_offset;
+   iface->get_text_at_offset = eail_label_get_text_at_offset;
+   iface->get_text_before_offset = eail_label_get_text_before_offset;
 }
 
index b7b78bf..d721dc1 100644 (file)
@@ -606,3 +606,744 @@ eail_notify_child_focus_changes(void)
     * been fully established*/
    _eail_notify_focus_listeners_delayed(1600);
 }
+
+/**
+ * @brief Returns the position that is obtained by adding count to the
+ * given offset
+ *
+ * Count may be positive or negative.
+ *
+ * @param textblock Evas textblock
+ * @param offset character offset
+ * @param count number of characters to move from offset
+ * @returns integer representing the new position
+ */
+static gint
+_eail_move_chars(const Evas_Object *textblock,
+                 gint offset,
+                 gint count)
+{
+   Evas_Textblock_Cursor *cur;
+   gint dir;
+   gboolean res;
+
+   dir = count > 0 ? 1 : -1;
+   cur = evas_object_textblock_cursor_new(textblock);
+   evas_textblock_cursor_pos_set(cur, offset);
+
+   while(count)
+     {
+        res = dir > 0 ? evas_textblock_cursor_char_next(cur) :
+            evas_textblock_cursor_char_prev(cur);
+        if (!res) break;
+
+        count -= dir;
+     }
+
+   offset = evas_textblock_cursor_pos_get(cur);
+   evas_textblock_cursor_free(cur);
+
+   return offset;
+}
+
+/**
+ * @brief Gets the utf8 character at offset
+ *
+ * @param textblock Evas textblock
+ * @param offset character offset
+ * @returns char representing the utf8 character
+ */
+static gunichar
+_eail_get_unichar_at_offset(const Evas_Object *textblock,
+                            int offset)
+{
+   Evas_Textblock_Cursor *cur;
+   gchar *s;
+   gunichar c;
+
+   cur = evas_object_textblock_cursor_new(textblock);
+   evas_textblock_cursor_pos_set(cur, offset);
+   s = evas_textblock_cursor_content_get(cur);
+   c = g_utf8_get_char(s);
+
+   evas_textblock_cursor_free(cur);
+   g_free(s);
+
+   return c;
+}
+
+/**
+ * @brief Checks whether the character at offset in textblock is a word's start
+ *
+ * @param textblock Evas textblock
+ * @param offset character offset
+ * @returns TRUE on success, FALSE otherwise
+ */
+static gboolean
+_eail_is_word_start(const Evas_Object *textblock,
+                    gint offset)
+{
+   /* first character in a word */
+   Evas_Textblock_Cursor *cur = NULL;
+   cur = evas_object_textblock_cursor_new(textblock);
+   evas_textblock_cursor_pos_set(cur, offset);
+   evas_textblock_cursor_word_start(cur);
+   gint pos = evas_textblock_cursor_pos_get(cur);
+   evas_textblock_cursor_free(cur);
+
+   return pos == offset;
+}
+
+/**
+ * @brief Checks whether the character at offset in textblock is a word's end
+ *
+ * @param textblock Evas textblock
+ * @param offset character offset
+ * @return TRUE on success, FALSE otherwise
+ */
+static gboolean
+_eail_is_word_end(const Evas_Object *textblock,
+                  gint offset)
+{
+   /* is first non-word char after a word */
+   Evas_Textblock_Cursor *cur = NULL;
+   cur = evas_object_textblock_cursor_new(textblock);
+   evas_textblock_cursor_pos_set(cur, offset - 2);
+   evas_textblock_cursor_word_end(cur);
+   gint pos = evas_textblock_cursor_pos_get(cur);
+   evas_textblock_cursor_free(cur);
+
+   return (pos + 1 == offset);
+}
+
+/**
+ * @brief Checks whether the character at offset in textblock is inside a word
+ *
+ * @param textblock Evas textblock
+ * @param offset character offset
+ * @returns TRUE on success, FALSE otherwise
+ */
+static gboolean
+_eail_is_inside_word(const Evas_Object *textblock,
+                     gint offset)
+{
+   Evas_Textblock_Cursor *cur = NULL;
+   cur = evas_object_textblock_cursor_new(textblock);
+   evas_textblock_cursor_pos_set(cur, offset);
+   evas_textblock_cursor_word_start(cur);
+   gint pos_start = evas_textblock_cursor_pos_get(cur);
+   evas_textblock_cursor_char_prev(cur);
+   evas_textblock_cursor_word_end(cur);
+   gint pos_end = evas_textblock_cursor_pos_get(cur);
+   evas_textblock_cursor_free(cur);
+
+   return (pos_start <= offset && pos_end >= offset);
+}
+
+/**
+ * @brief Gets the texblock length
+ *
+ * @param textblock Evas textblock
+ * @returns integer representing the textblock length
+ */
+static gint
+_eail_get_len(const Evas_Object *textblock)
+{
+   Evas_Textblock_Cursor *cur;
+   int ctr = 0;
+
+   cur = evas_object_textblock_cursor_new(textblock);
+   while (evas_textblock_cursor_char_next(cur))
+     ++ctr;
+
+   evas_textblock_cursor_free(cur);
+
+   return ctr;
+}
+
+/**
+ * @brief Returns the position that is count words from the given offset
+ *
+ * Count may  be positive or negative. If count is positive, the returned
+ * position will be a word end, otherwise it will be a word start.
+ *
+ * @param textblock Evas textblock
+ * @param offset a character offset
+ * @param count the number of words to move from offset
+ * @returns integer representing the new position
+ */
+static gint
+_eail_move_words(const Evas_Object *textblock,
+                 gint offset,
+                 gint count)
+{
+   gint len = _eail_get_len(textblock);
+
+   while (count > 0 && offset < len)
+     {
+        do
+          offset++;
+        while (offset < len && !_eail_is_word_end(textblock, offset));
+
+        count--;
+     }
+   while (count < 0 && offset > 0)
+     {
+        do
+          offset--;
+        while (offset > 0 && !_eail_is_word_start(textblock, offset));
+
+        count++;
+     }
+
+   return offset;
+}
+
+/**
+ * @brief Checks whether the character is sentence break
+ *
+ * @param c character
+ * @returns TRUE on success, FALSE otherwise
+ */
+static gboolean
+_eail_is_sentence_break(gunichar c)
+{
+   if (c == '.' || c == '?' || c == '!') return TRUE;
+
+   return FALSE;
+}
+
+/**
+ * @brief Checks whether the character at offset in textblock is a sentence's start
+ *
+ * @param textblock Evas textblock
+ * @param offset character offset
+ * @returns TRUE on success, FALSE otherwise
+ */
+static gboolean
+_eail_is_sentence_start(const Evas_Object *textblock,
+                        gint offset)
+{
+   gunichar c;
+   gint len = _eail_get_len(textblock);
+
+   if (offset > len -1 || offset < 0) return FALSE;
+
+   if (0 == offset) return TRUE;
+
+   c = _eail_get_unichar_at_offset(textblock, offset - 1);
+   if (_eail_is_sentence_break(c)) return TRUE;
+
+   return FALSE;
+}
+
+/**
+ * @brief Checks whether the character at offset in textblock is a sentence's end
+ *
+ * @param textblock Evas textblock
+ * @param offset character offset
+ * @return TRUE on success, FALSE otherwise
+ */
+static gboolean
+_eail_is_sentence_end(const Evas_Object *textblock,
+                      gint offset)
+{
+   gunichar c;
+   gint len = _eail_get_len(textblock);
+
+   if (offset > len -1 || offset < 0) return FALSE;
+
+   if (offset == len -1) return TRUE;
+
+   c = _eail_get_unichar_at_offset(textblock, offset);
+   if (_eail_is_sentence_break(c)) return TRUE;
+
+   return FALSE;
+}
+
+/**
+ * @brief Checks whether the character at offset in textblock is inside a senetence
+ *
+ * @param textblock Evas textblock
+ * @param offset character offset
+ * @returns TRUE on success, FALSE otherwise
+ */
+static gboolean
+_eail_is_inside_sentence(const Evas_Object *textblock,
+                         gint offset)
+{
+   gunichar c;
+   gint len = _eail_get_len(textblock);
+
+   if ((offset > len -1 || offset < 0)) return FALSE;
+
+   c = _eail_get_unichar_at_offset(textblock, offset);
+
+   if (!_eail_is_sentence_break(c)) return TRUE;
+
+   return FALSE;
+}
+
+/**
+ * @brief Returns the position that is count sentences from the given offset
+ *
+ * Count may  be positive or negative. If count is positive, the returned
+ * position will be a sentence end, otherwise it will be a sentence start.
+ *
+ * @param textblock Evas textblock
+ * @param offset a character offset
+ * @param count the number of words to move from offset
+ * @returns integer representing the new position
+ */
+static gint
+_eail_move_sentences(const Evas_Object *textblock,
+                      gint offset,
+                      gint count)
+{
+   gint len = _eail_get_len(textblock);
+
+   while (count > 0 && offset < len)
+     {
+        do
+          offset++;
+        while (offset < len && !_eail_is_sentence_end(textblock, offset));
+
+        count--;
+     }
+   while (count < 0 && offset > 0)
+     {
+        do
+          offset--;
+        while (offset > 0 && !_eail_is_sentence_start(textblock, offset));
+
+        count++;
+     }
+
+   return offset;
+}
+
+/**
+ * @brief Checks whether the character at offset in textblock is a line's start
+ *
+ * @param textblock Evas textblock
+ * @param offset character offset
+ * @returns TRUE on success, FALSE otherwise
+ */
+static gboolean
+_eail_is_line_start(const Evas_Object *textblock,
+                    gint offset)
+{
+   Evas_Textblock_Cursor *cur = NULL;
+   cur = evas_object_textblock_cursor_new(textblock);
+   evas_textblock_cursor_pos_set(cur, offset);
+   evas_textblock_cursor_line_char_first(cur);
+   gint pos = evas_textblock_cursor_pos_get(cur);
+   evas_textblock_cursor_free(cur);
+
+   return pos == offset;
+}
+
+/**
+ * @brief Checks whether the character at offset in textblock is a line's end
+ *
+ * @param textblock Evas textblock
+ * @param offset character offset
+ * @return TRUE on success, FALSE otherwise
+ */
+static gboolean
+_eail_is_line_end(const Evas_Object *textblock,
+                  gint offset)
+{
+   /* is first non-word char after a word */
+   Evas_Textblock_Cursor *cur = NULL;
+   cur = evas_object_textblock_cursor_new(textblock);
+   evas_textblock_cursor_pos_set(cur, offset);
+   evas_textblock_cursor_line_char_last(cur);
+   gint pos = evas_textblock_cursor_pos_get(cur);
+   evas_textblock_cursor_free(cur);
+
+   return (pos == offset);
+}
+
+/**
+ * @brief Checks whether the character at offset in textblock is inside a line
+ *
+ * @param textblock Evas textblock
+ * @param offset character offset
+ * @returns TRUE on success, FALSE otherwise
+ */
+static gboolean
+_eail_is_inside_line(const Evas_Object *textblock,
+                     gint offset)
+{
+   Evas_Textblock_Cursor *cur = NULL;
+   cur = evas_object_textblock_cursor_new(textblock);
+   evas_textblock_cursor_pos_set(cur, offset);
+   evas_textblock_cursor_line_char_last(cur);
+   gint pos_end = evas_textblock_cursor_pos_get(cur);
+   evas_textblock_cursor_free(cur);
+   return pos_end != offset;
+}
+
+/**
+ * @brief Returns the position that is count lines from the given offset
+ *
+ * Count may  be positive or negative. If count is positive, the returned
+ * position will be a line end, otherwise it will be a line start.
+ *
+ * @param textblock Evas textblock
+ * @param offset a character offset
+ * @param count the number of words to move from offset
+ * @returns integer representing the new position
+ */
+static gint
+_eail_move_lines(const Evas_Object *textblock,
+                 gint offset,
+                 gint count)
+{
+   gint len = _eail_get_len(textblock);
+
+   while (count > 0 && offset < len)
+     {
+        do
+          offset++;
+        while (offset < len && !_eail_is_line_end(textblock, offset));
+
+        count--;
+     }
+   while (count < 0 && offset > 0)
+     {
+        do
+          offset--;
+        while (offset > 0 && !_eail_is_line_start(textblock, offset));
+
+        count++;
+     }
+
+   return offset;
+}
+
+/**
+ * @brief Gets a slice of the text from textblock after offset
+ *
+ * Use g_free() to free the returned string.
+ *
+ * @param textblock Evas textblock
+ * @param offset character offset
+ * @param boundary_type AtkTextBoundary instance
+ * @param [out] start_offset start position of the returned text
+ * @param [out] end_offset end position of the returned text
+ * @returns newly allocated string containg a slice of text from textblock
+ */
+gchar *
+eail_get_text_after(const Evas_Object *textblock,
+                    gint offset,
+                    AtkTextBoundary boundary_type,
+                    gint *start_offset,
+                    gint *end_offset)
+{
+   const gchar *text;
+   int len;
+   gint start, end;
+
+   text = evas_textblock_text_markup_to_utf8(
+       textblock, evas_object_textblock_text_markup_get(textblock));
+   if (!text)
+     {
+        *start_offset = 0;
+        *end_offset = 0;
+        return g_strdup("");
+     }
+
+   start = offset;
+   end = offset;
+   len = _eail_get_len(textblock);
+
+   switch (boundary_type)
+     {
+       case ATK_TEXT_BOUNDARY_CHAR:
+           start = _eail_move_chars(textblock, start, 1);
+           end = start;
+           end = _eail_move_chars(textblock, end, 1);
+           break;
+
+       case ATK_TEXT_BOUNDARY_WORD_START:
+           if (_eail_is_inside_word(textblock, end))
+             end = _eail_move_words(textblock, end, 1);
+           while (!_eail_is_word_start(textblock, end) && end < len)
+             end = _eail_move_chars(textblock, end, 1);
+           start = end;
+           if (end < len)
+             {
+                end = _eail_move_words(textblock, end, 1);
+                while (!_eail_is_word_start(textblock, end) && end < len)
+                  end = _eail_move_chars(textblock, end, 1);
+             }
+           break;
+
+       case ATK_TEXT_BOUNDARY_WORD_END:
+           end = _eail_move_words(textblock, end, 1);
+           start = end;
+           if (end < len)
+             end = _eail_move_words(textblock, end, 1);
+           break;
+
+       case ATK_TEXT_BOUNDARY_SENTENCE_START:
+           if (_eail_is_inside_sentence(textblock, end))
+             end = _eail_move_sentences(textblock, end, 1);
+           while (!_eail_is_sentence_start(textblock, end) && end < len)
+             end = _eail_move_chars(textblock, end, 1);
+           start = end;
+           if (end < len)
+             {
+                end = _eail_move_sentences(textblock, end, 1);
+                while (!_eail_is_sentence_start(textblock, end) && end < len)
+                  end = _eail_move_chars(textblock, end, 1);
+             }
+           break;
+
+       case ATK_TEXT_BOUNDARY_SENTENCE_END:
+           end = _eail_move_sentences(textblock, end, 1);
+           start = end;
+           if (end < len)
+             end = _eail_move_sentences(textblock, end, 1);
+           break;
+
+       case ATK_TEXT_BOUNDARY_LINE_START:
+           if (_eail_is_inside_line(textblock, end))
+             end = _eail_move_lines(textblock, end, 1);
+           while (!_eail_is_line_start(textblock, end) && end < len)
+             end = _eail_move_chars(textblock, end, 1);
+           start = end;
+           if (end < len)
+             {
+                end = _eail_move_lines(textblock, end, 1);
+                while (!_eail_is_line_start(textblock, end) && end < len)
+                  end = _eail_move_chars(textblock, end, 1);
+             }
+           break;
+
+       case ATK_TEXT_BOUNDARY_LINE_END:
+           end = _eail_move_lines(textblock, end, 1);
+           start = end;
+           if (end < len)
+             end = _eail_move_lines(textblock, end, 1);
+           break;
+     }
+
+   *start_offset = start;
+   *end_offset = end;
+   g_assert(start <= end);
+
+   return g_utf8_substring(text, start, end);
+}
+
+/**
+ * @brief Gets a slice of the text from textblock at offset
+ *
+ * Use g_free() to free the returned string.
+ *
+ * @param textblock Evas textblock
+ * @param offset character offset
+ * @param boundary_type AtkTextBoundary instance
+ * @param [out] start_offset start position of the returned text
+ * @param [out] end_offset end position of the return text
+ * @returns newly allocated string containing a slice of text from textblock
+ */
+gchar *
+eail_get_text_at(const Evas_Object *textblock,
+                 gint offset,
+                 AtkTextBoundary boundary_type,
+                 gint *start_offset,
+                 gint *end_offset)
+{
+   const gchar *text;
+   int len;
+   gint start, end;
+
+   text = evas_textblock_text_markup_to_utf8(
+       textblock, evas_object_textblock_text_markup_get(textblock));
+   if (!text)
+     {
+        *start_offset = 0;
+        *end_offset = 0;
+        return g_strdup("");
+     }
+
+   start = offset;
+   end = offset;
+   len = _eail_get_len(textblock);
+
+   switch (boundary_type)
+     {
+       case ATK_TEXT_BOUNDARY_CHAR:
+           end = _eail_move_chars(textblock, end, 1);
+           break;
+
+       case ATK_TEXT_BOUNDARY_WORD_START:
+           if (!_eail_is_word_start(textblock, start))
+             start = _eail_move_words(textblock, start, -1);
+           if (_eail_is_inside_word(textblock, end))
+             end = _eail_move_words(textblock, end, 1);
+           while (!_eail_is_word_start(textblock, end) && end < len)
+             end = _eail_move_chars(textblock, end, 1);
+           break;
+
+       case ATK_TEXT_BOUNDARY_WORD_END:
+           if (_eail_is_inside_word(textblock, start) &&
+               !_eail_is_word_start(textblock, start))
+             start = _eail_move_words(textblock, start, -1);
+           while (!_eail_is_word_end(textblock, start) && start > 0)
+             start = _eail_move_chars(textblock, start, -1);
+           end = _eail_move_words(textblock, end, 1);
+           break;
+
+       case ATK_TEXT_BOUNDARY_SENTENCE_START:
+           if (!_eail_is_sentence_start(textblock, start))
+             start = _eail_move_sentences(textblock, start, -1);
+           if (_eail_is_inside_sentence(textblock, end))
+             end = _eail_move_sentences(textblock, end, 1);
+           while (!_eail_is_sentence_start(textblock, end) && end < len)
+             end = _eail_move_chars(textblock, end, 1);
+           break;
+
+       case ATK_TEXT_BOUNDARY_SENTENCE_END:
+           if (_eail_is_inside_sentence(textblock, start) &&
+               !_eail_is_sentence_start(textblock, start))
+             start = _eail_move_sentences(textblock, start, -1);
+           while (!_eail_is_sentence_end(textblock, start) && start > 0)
+             start = _eail_move_chars(textblock, start, -1);
+           end = _eail_move_sentences(textblock, end, 1);
+           break;
+
+       case ATK_TEXT_BOUNDARY_LINE_START:
+           if (!_eail_is_line_start(textblock, start))
+             start = _eail_move_lines(textblock, start, -1);
+           if (_eail_is_inside_line(textblock, end))
+             end = _eail_move_lines(textblock, end, 1);
+           while (!_eail_is_line_start(textblock, end) && end < len)
+             end = _eail_move_chars(textblock, end, 1);
+           break;
+
+       case ATK_TEXT_BOUNDARY_LINE_END:
+           if (_eail_is_inside_line(textblock, start) &&
+               !_eail_is_line_start(textblock, start))
+             start = _eail_move_lines(textblock, start, -1);
+           while (!_eail_is_line_end(textblock, start) && start > 0)
+             start = _eail_move_chars(textblock, start, -1);
+           end = _eail_move_lines(textblock, end, 1);
+           break;
+     }
+
+   *start_offset = start;
+   *end_offset = end;
+   g_assert(start <= end);
+
+   return g_utf8_substring(text, start, end);
+}
+
+/**
+ * @brief Gets a slice of the text from textblock before offset
+ *
+ * Use g_free() to free the returned string.
+ *
+ * @param textblock Evas textblock
+ * @param offset character offset
+ * @param boundary_type AtkTextBoundary instance
+ * @param [out] start_offset start position of the returned text
+ * @param [out] end_offset end position of the returned text
+ * @returns newly allocated string containing a slice of text from textblock
+ */
+gchar *
+eail_get_text_before(const Evas_Object *textblock,
+                     gint offset,
+                     AtkTextBoundary boundary_type,
+                     gint *start_offset,
+                     gint *end_offset)
+{
+   const gchar *text;
+   gint start, end;
+
+   text = evas_textblock_text_markup_to_utf8(
+       textblock, evas_object_textblock_text_markup_get(textblock));
+   if (!text)
+     {
+        *start_offset = 0;
+        *end_offset = 0;
+        return g_strdup("");
+     }
+
+   start = offset;
+   end = offset;
+
+   switch (boundary_type)
+     {
+       case ATK_TEXT_BOUNDARY_CHAR:
+           start = _eail_move_chars(textblock, start, -1);
+           break;
+
+       case ATK_TEXT_BOUNDARY_WORD_START:
+           if (!_eail_is_word_start(textblock, start))
+             start = _eail_move_words(textblock, start, -1);
+           end = start;
+           start = _eail_move_words(textblock, start, -1);
+           break;
+
+       case ATK_TEXT_BOUNDARY_WORD_END:
+           if (_eail_is_inside_word(textblock, start) &&
+               !_eail_is_word_start(textblock, start))
+             start = _eail_move_words(textblock, start, -1);
+           while (!_eail_is_word_end(textblock, start) && start > 0)
+             start = _eail_move_chars(textblock, start, -1);
+           end = start;
+           start = _eail_move_words(textblock, start, -1);
+           while (!_eail_is_word_end(textblock, start) && start > 0)
+             start = _eail_move_chars(textblock, start, -1);
+           break;
+
+       case ATK_TEXT_BOUNDARY_SENTENCE_START:
+           if (!_eail_is_sentence_start(textblock, start))
+             start = _eail_move_sentences(textblock, start, -1);
+           end = start;
+           start = _eail_move_sentences(textblock, start, -1);
+           break;
+
+       case ATK_TEXT_BOUNDARY_SENTENCE_END:
+           if (_eail_is_inside_sentence(textblock, start) &&
+               !_eail_is_sentence_start(textblock, start))
+             start = _eail_move_sentences(textblock, start, -1);
+           while (!_eail_is_sentence_end(textblock, start) && start > 0)
+             start = _eail_move_chars(textblock, start, -1);
+           end = start;
+           start = _eail_move_sentences(textblock, start, -1);
+           while (!_eail_is_sentence_end(textblock, start) && start > 0)
+             start = _eail_move_chars(textblock, start, -1);
+           break;
+
+       case ATK_TEXT_BOUNDARY_LINE_START:
+           if (!_eail_is_line_start(textblock, start))
+             start = _eail_move_lines(textblock, start, -1);
+           end = start;
+           start = _eail_move_lines(textblock, start, -1);
+           break;
+
+       case ATK_TEXT_BOUNDARY_LINE_END:
+           if (_eail_is_inside_line(textblock, start) &&
+               !_eail_is_line_start(textblock, start))
+             start = _eail_move_lines(textblock, start, -1);
+           while (!_eail_is_line_end(textblock, start) && start > 0)
+             start = _eail_move_chars(textblock, start, -1);
+           end = start;
+           start = _eail_move_lines(textblock, start, -1);
+           while (!_eail_is_line_end(textblock, start) && start > 0)
+             start = _eail_move_chars(textblock, start, -1);
+           break;
+
+     }
+
+   *start_offset = start;
+   *end_offset = end;
+   g_assert(start <= end);
+
+   return g_utf8_substring(text, start, end);
+}
index 31c8364..d712b61 100644 (file)
@@ -184,6 +184,61 @@ void eail_emit_children_changed_obj(gboolean added,
  */
 void eail_notify_child_focus_changes(void);
 
+/**
+ * @brief Helper function to get a slice of the text from textblock after offset
+ *
+ * Use g_free() to free the returned string.
+ *
+ * @param textblock Evas textblock
+ * @param offset character offset
+ * @param boundary_type AtkTextBoundary instance
+ * @param [out] start_offset start position of the returned text
+ * @param [out] end_offset end position of the returned text
+ * @returns newly allocated string containg a slice of text from textblock
+ */
+gchar *
+eail_get_text_after(const Evas_Object *textblock,
+                    gint offset,
+                    AtkTextBoundary boundary_type,
+                    gint *start_offset,
+                    gint *end_offset);
+/**
+ * @brief Helper function to get a slice of the text from textblock at offset
+ *
+ * Use g_free() to free the returned string.
+ *
+ * @param textblock Evas textblock
+ * @param offset character offset
+ * @param boundary_type AtkTextBoundary instance
+ * @param [out] start_offset start position of the returned text
+ * @param [out] end_offset end position of the return text
+ * @returns newly allocated string containing a slice of text from textblock
+ */
+gchar *
+eail_get_text_at(const Evas_Object *textblock,
+                 gint offset,
+                 AtkTextBoundary boundary_type,
+                 gint *start_offset,
+                 gint *end_offset);
+/**
+ * @brief Helper function to get a slice of the text from textblock before offset
+ *
+ * Use g_free() to free the returned string.
+ *
+ * @param textblock Evas textblock
+ * @param entry entry widget instance
+ * @param offset character offset
+ * @param boundary_type AtkTextBoundary instance
+ * @param [out] start_offset start position of the returned text
+ * @param [out] end_offset end position of the returned text
+ * @returns newly allocated string containing a slice of text from textblock
+ */
+gchar *
+eail_get_text_before(const Evas_Object *textblock,
+                     gint offset,
+                     AtkTextBoundary boundary_type,
+                     gint *start_offset,
+                     gint *end_offset);
 #ifdef __cplusplus
 }
 #endif