[gtk+] textbuffer: nicer get_iter functions, without return values



commit 1685da6f696166588357b2e999da082cf731518f
Author: Sébastien Wilmet <swilmet gnome org>
Date:   Thu Nov 12 17:43:32 2015 +0100

    textbuffer: nicer get_iter functions, without return values
    
    Avoid crashes when passing an invalid location to a
    gtk_text_buffer_get_iter_at_*() function.
    
    A first attempt added boolean return values to know if @iter has been set to
    the exact location, but it breaks Python and JS bindings because the out
    parameter is already a return value in those languages.
    
    Unit tests are added.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=735341

 gtk/gtktextbuffer.c        |   61 ++++++++++++++++++----
 testsuite/gtk/textbuffer.c |  123 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 174 insertions(+), 10 deletions(-)
---
diff --git a/gtk/gtktextbuffer.c b/gtk/gtktextbuffer.c
index 36c5ed4..41ef4a3 100644
--- a/gtk/gtktextbuffer.c
+++ b/gtk/gtktextbuffer.c
@@ -2863,10 +2863,14 @@ gtk_text_buffer_remove_all_tags (GtkTextBuffer     *buffer,
  * @line_number: line number counting from 0
  * @char_offset: char offset from start of line
  *
- * Obtains an iterator pointing to @char_offset within the given
- * line. The @char_offset must exist, offsets off the end of the line
- * are not allowed. Note characters, not bytes;
- * UTF-8 may encode one character as multiple bytes.
+ * Obtains an iterator pointing to @char_offset within the given line. Note
+ * characters, not bytes; UTF-8 may encode one character as multiple bytes.
+ *
+ * Before the 3.20 version, it was not allowed to pass an invalid location.
+ *
+ * Since the 3.20 version, if @line_number is greater than the number of lines
+ * in the @buffer, the end iterator is returned. And if @char_offset is off the
+ * end of the line, the iterator at the end of the line is returned.
  **/
 void
 gtk_text_buffer_get_iter_at_line_offset (GtkTextBuffer *buffer,
@@ -2874,11 +2878,27 @@ gtk_text_buffer_get_iter_at_line_offset (GtkTextBuffer *buffer,
                                          gint           line_number,
                                          gint           char_offset)
 {
+  GtkTextIter end_line_iter;
+
   g_return_if_fail (iter != NULL);
   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
 
-  _gtk_text_btree_get_iter_at_line_char (get_btree (buffer),
-                                         iter, line_number, char_offset);
+  if (line_number >= gtk_text_buffer_get_line_count (buffer))
+    {
+      gtk_text_buffer_get_end_iter (buffer, iter);
+      return;
+    }
+
+  _gtk_text_btree_get_iter_at_line_char (get_btree (buffer), iter, line_number, 0);
+
+  end_line_iter = *iter;
+  if (!gtk_text_iter_ends_line (&end_line_iter))
+    gtk_text_iter_forward_to_line_end (&end_line_iter);
+
+  if (char_offset <= gtk_text_iter_get_line_offset (&end_line_iter))
+    gtk_text_iter_set_line_offset (iter, char_offset);
+  else
+    *iter = end_line_iter;
 }
 
 /**
@@ -2889,9 +2909,14 @@ gtk_text_buffer_get_iter_at_line_offset (GtkTextBuffer *buffer,
  * @byte_index: byte index from start of line
  *
  * Obtains an iterator pointing to @byte_index within the given line.
- * @byte_index must be the start of a UTF-8 character, and must not be
- * beyond the end of the line.  Note bytes, not
+ * @byte_index must be the start of a UTF-8 character. Note bytes, not
  * characters; UTF-8 may encode one character as multiple bytes.
+ *
+ * Before the 3.20 version, it was not allowed to pass an invalid location.
+ *
+ * Since the 3.20 version, if @line_number is greater than the number of lines
+ * in the @buffer, the end iterator is returned. And if @byte_index is off the
+ * end of the line, the iterator at the end of the line is returned.
  **/
 void
 gtk_text_buffer_get_iter_at_line_index  (GtkTextBuffer *buffer,
@@ -2899,11 +2924,27 @@ gtk_text_buffer_get_iter_at_line_index  (GtkTextBuffer *buffer,
                                          gint           line_number,
                                          gint           byte_index)
 {
+  GtkTextIter end_line_iter;
+
   g_return_if_fail (iter != NULL);
   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
 
-  _gtk_text_btree_get_iter_at_line_byte (get_btree (buffer),
-                                         iter, line_number, byte_index);
+  if (line_number >= gtk_text_buffer_get_line_count (buffer))
+    {
+      gtk_text_buffer_get_end_iter (buffer, iter);
+      return;
+    }
+
+  gtk_text_buffer_get_iter_at_line (buffer, iter, line_number);
+
+  end_line_iter = *iter;
+  if (!gtk_text_iter_ends_line (&end_line_iter))
+    gtk_text_iter_forward_to_line_end (&end_line_iter);
+
+  if (byte_index <= gtk_text_iter_get_line_index (&end_line_iter))
+    gtk_text_iter_set_line_index (iter, byte_index);
+  else
+    *iter = end_line_iter;
 }
 
 /**
diff --git a/testsuite/gtk/textbuffer.c b/testsuite/gtk/textbuffer.c
index efdbd44..e1d0e88 100644
--- a/testsuite/gtk/textbuffer.c
+++ b/testsuite/gtk/textbuffer.c
@@ -1434,6 +1434,128 @@ test_clipboard (void)
   g_object_unref (buffer);
 }
 
+static void
+test_get_iter (void)
+{
+  GtkTextBuffer *buffer;
+  GtkTextIter iter;
+  gint offset;
+
+  buffer = gtk_text_buffer_new (NULL);
+
+  /* ß takes 2 bytes in UTF-8 */
+  gtk_text_buffer_set_text (buffer, "ab\nßd\r\nef", -1);
+
+  /* Test get_iter_at_line() */
+  gtk_text_buffer_get_iter_at_line (buffer, &iter, 0);
+  g_assert (gtk_text_iter_is_start (&iter));
+
+  gtk_text_buffer_get_iter_at_line (buffer, &iter, 1);
+  offset = gtk_text_iter_get_offset (&iter);
+  g_assert_cmpint (offset, ==, 3);
+
+  gtk_text_buffer_get_iter_at_line (buffer, &iter, 2);
+  offset = gtk_text_iter_get_offset (&iter);
+  g_assert_cmpint (offset, ==, 7);
+
+  gtk_text_buffer_get_iter_at_line (buffer, &iter, 3);
+  g_assert (gtk_text_iter_is_end (&iter));
+
+  /* Test get_iter_at_line_offset() */
+  gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 0, 0);
+  g_assert (gtk_text_iter_is_start (&iter));
+
+  gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 0, 1);
+  offset = gtk_text_iter_get_offset (&iter);
+  g_assert_cmpint (offset, ==, 1);
+
+  gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 0, 2);
+  offset = gtk_text_iter_get_offset (&iter);
+  g_assert_cmpint (offset, ==, 2);
+
+  gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 0, 3);
+  offset = gtk_text_iter_get_offset (&iter);
+  g_assert_cmpint (offset, ==, 2);
+
+  gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 1, 1);
+  offset = gtk_text_iter_get_offset (&iter);
+  g_assert_cmpint (offset, ==, 4);
+
+  gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 2, 1);
+  offset = gtk_text_iter_get_offset (&iter);
+  g_assert_cmpint (offset, ==, 8);
+
+  gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 2, 2);
+  g_assert (gtk_text_iter_is_end (&iter));
+
+  gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 2, 3);
+  g_assert (gtk_text_iter_is_end (&iter));
+
+  gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 3, 1);
+  g_assert (gtk_text_iter_is_end (&iter));
+
+  /* Test get_iter_at_line_index() */
+  gtk_text_buffer_get_iter_at_line_index (buffer, &iter, 0, 0);
+  g_assert (gtk_text_iter_is_start (&iter));
+
+  gtk_text_buffer_get_iter_at_line_index (buffer, &iter, 0, 1);
+  offset = gtk_text_iter_get_offset (&iter);
+  g_assert_cmpint (offset, ==, 1);
+
+  gtk_text_buffer_get_iter_at_line_index (buffer, &iter, 0, 2);
+  offset = gtk_text_iter_get_offset (&iter);
+  g_assert_cmpint (offset, ==, 2);
+
+  gtk_text_buffer_get_iter_at_line_index (buffer, &iter, 0, 3);
+  offset = gtk_text_iter_get_offset (&iter);
+  g_assert_cmpint (offset, ==, 2);
+
+  gtk_text_buffer_get_iter_at_line_index (buffer, &iter, 1, 0);
+  offset = gtk_text_iter_get_offset (&iter);
+  g_assert_cmpint (offset, ==, 3);
+
+  gtk_text_buffer_get_iter_at_line_index (buffer, &iter, 1, 2);
+  offset = gtk_text_iter_get_offset (&iter);
+  g_assert_cmpint (offset, ==, 4);
+
+  gtk_text_buffer_get_iter_at_line_index (buffer, &iter, 1, 3);
+  offset = gtk_text_iter_get_offset (&iter);
+  g_assert_cmpint (offset, ==, 5);
+
+  gtk_text_buffer_get_iter_at_line_index (buffer, &iter, 2, 2);
+  g_assert (gtk_text_iter_is_end (&iter));
+
+  gtk_text_buffer_get_iter_at_line_index (buffer, &iter, 2, 3);
+  g_assert (gtk_text_iter_is_end (&iter));
+
+  gtk_text_buffer_get_iter_at_line_index (buffer, &iter, 3, 1);
+  g_assert (gtk_text_iter_is_end (&iter));
+
+  /* Test get_iter_at_offset() */
+  gtk_text_buffer_get_iter_at_offset (buffer, &iter, 0);
+  g_assert (gtk_text_iter_is_start (&iter));
+
+  gtk_text_buffer_get_iter_at_offset (buffer, &iter, 1);
+  offset = gtk_text_iter_get_offset (&iter);
+  g_assert_cmpint (offset, ==, 1);
+
+  gtk_text_buffer_get_iter_at_offset (buffer, &iter, 8);
+  offset = gtk_text_iter_get_offset (&iter);
+  g_assert_cmpint (offset, ==, 8);
+  g_assert (!gtk_text_iter_is_end (&iter));
+
+  gtk_text_buffer_get_iter_at_offset (buffer, &iter, 9);
+  g_assert (gtk_text_iter_is_end (&iter));
+
+  gtk_text_buffer_get_iter_at_offset (buffer, &iter, 100);
+  g_assert (gtk_text_iter_is_end (&iter));
+
+  gtk_text_buffer_get_iter_at_offset (buffer, &iter, -1);
+  g_assert (gtk_text_iter_is_end (&iter));
+
+  g_object_unref (buffer);
+}
+
 int
 main (int argc, char** argv)
 {
@@ -1452,6 +1574,7 @@ main (int argc, char** argv)
   g_test_add_func ("/TextBuffer/Fill and Empty", test_fill_empty);
   g_test_add_func ("/TextBuffer/Tag", test_tag);
   g_test_add_func ("/TextBuffer/Clipboard", test_clipboard);
+  g_test_add_func ("/TextBuffer/Get iter", test_get_iter);
 
   return g_test_run();
 }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]